Website search example 2

Here’s an example of search in a custom data type, including faceted search and search results sorting:

public class ProductSearchQuery
{
	public ProductSearchQuery(CultureInfo culture, string text)
	{
		Culture = culture;
		Text = text;
	}

	public CultureInfo Culture { get; }
	public string Text { get; }

	public int PageSize { get; set; } = 50;
	public int PageNumber { get; set; } = 0;
	public ICollection<string> SelectedTags { get; set; } = new string[0];

	public ProductSortByField SortBy { get; set; }
	public bool SortDescending { get; set; }
}

public enum ProductSortByField
{
	None = 0,
	Label = 1,
}

public class ProductSearchResult
{
	public ICollection<ProductSearchResultEntry> Products { get; set; }
	public int TotalDocumentsFound { get; set; }
	public KeyValuePair<string, int>[] TagFacets { get; set; }
}

public class ProductSearchResultEntry
{
	public string Label { get; set; }
	public string Description { get; set; }
	public string Tags { get; set; }
	public string Url { get; set; }
}

public class ProductSearch
{
	private readonly ISearchProvider _searchProvider;

	public ProductSearch(ISearchProvider searchProvider)
	{
		_searchProvider = searchProvider ?? throw new ArgumentNullException(nameof(searchProvider));
	}

	public async Task<ProductSearchResult> SearchAsync(ProductSearchQuery query)
	{
		var searchQuery = new SearchQuery(query.Text, query.Culture)
		{
			MaxDocumentsNumber = query.PageSize,
			SearchResultOffset = query.PageNumber * query.PageSize
		};

		searchQuery.ShowOnlyDocumentsWithUrls();
		searchQuery.FilterByDataTypes(typeof(Product));

		// Adding the "product.tags" field to the search query so the facet is returned 
		// as a part of the search results and filtering by the selected tags
		searchQuery.AddFieldFacet(ProductSearchDocumentSource.TagsFieldName, query.SelectedTags?.ToArray(), null);
		// Sorting the search results
		searchQuery.SortOptions = GetSortOptions(query.SortBy, query.SortDescending);

		var result = await _searchProvider.SearchAsync(searchQuery);
		return new ProductSearchResult
		{
			Products = result.Documents.Select(ToSearchResultEntry).ToList(),
			TotalDocumentsFound = result.TotalHits,
			TagFacets = GetSelectedTags(result)
		};
	}

	private KeyValuePair<string, int>[] GetSelectedTags(Composite.Search.SearchResult result)
	{
		var facet = result.Facets?.FirstOrDefault(kvp => kvp.Key == ProductSearchDocumentSource.TagsFieldName);
		return facet?.Value.Select(f => new KeyValuePair<string, int>(f.Value, f.HitCount)).ToArray();
	}

	private SearchQuerySortOption[] GetSortOptions(ProductSortByField field, bool reverseOrder)
	{
		if (field == ProductSortByField.None) return null;

		if (field == ProductSortByField.Label)
		{
			return new []
			{
				new SearchQuerySortOption(DefaultDocumentFieldNames.Label, reverseOrder)
			};
		}

		throw new InvalidOperationException("Not supported product sort field " + field);
	}

	private ProductSearchResultEntry ToSearchResultEntry(SearchDocument doc)
	{
		object tags,  desc;
		doc.FieldValues.TryGetValue(DefaultDocumentFieldNames.Description, out desc);
		doc.FieldValues.TryGetValue(_tagsDocumentField.Name, out tags);

		return new ProductSearchResultEntry
		{
			Label = doc.Label,
			Description = desc as string,
			Tags = (string) tags,
			Url = doc.Url
		};
	}
}

Result example: