public IHttpActionResult Search(string store, string[] priceLists, [ModelBinder(typeof(SearchParametersBinder))] SearchParameters parameters, [FromUri] coreModel.ItemResponseGroup responseGroup = coreModel.ItemResponseGroup.ItemMedium, [FromUri] string outline = "", string language = "en-us", string currency = "USD") { var context = new Dictionary<string, object> { { "StoreId", store }, }; var fullLoadedStore = GetStoreById(store); if (fullLoadedStore == null) { throw new NullReferenceException(store + " not found"); } var catalog = fullLoadedStore.Catalog; string categoryId = null; var criteria = new CatalogIndexedSearchCriteria { Locale = language, Catalog = catalog.ToLowerInvariant() }; if (!string.IsNullOrWhiteSpace(outline)) { criteria.Outlines.Add(String.Format("{0}/{1}*", catalog, outline)); categoryId = outline.Split(new[] { '/' }).Last(); context.Add("CategoryId", categoryId); } #region Filters // Now fill in filters var filters = _browseFilterService.GetFilters(context); // Add all filters foreach (var filter in filters) { criteria.Add(filter); } // apply terms if (parameters.Terms != null && parameters.Terms.Count > 0) { foreach (var term in parameters.Terms) { var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, term.Value); criteria.Apply(appliedFilter); } } #endregion #region Facets // apply facet filters var facets = parameters.Facets; if (facets.Count != 0) { foreach (var key in facets.Keys) { var filter = filters.SingleOrDefault( x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, facets[key]); criteria.Apply(appliedFilter); } } #endregion //criteria.ClassTypes.Add("Product"); criteria.RecordsToRetrieve = parameters.PageSize == 0 ? 10 : parameters.PageSize; criteria.StartingRecord = parameters.StartingRecord; criteria.Pricelists = priceLists; criteria.Currency = currency; criteria.StartDateFrom = parameters.StartDateFrom; criteria.SearchPhrase = parameters.FreeSearch; #region sorting if (!string.IsNullOrEmpty(parameters.Sort)) { var isDescending = "desc".Equals(parameters.SortOrder, StringComparison.OrdinalIgnoreCase); SearchSort sortObject = null; switch (parameters.Sort.ToLowerInvariant()) { case "price": if (criteria.Pricelists != null) { sortObject = new SearchSort( criteria.Pricelists.Select( priceList => new SearchSortField(String.Format("price_{0}_{1}", criteria.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Format("sort{0}{1}", catalog, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(criteria.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(criteria.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } criteria.Sort = sortObject; } #endregion //Load ALL products var searchResults = _browseService.SearchItems(criteria, responseGroup); // populate inventory if ((responseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties) { PopulateInventory(fullLoadedStore.FulfillmentCenter, searchResults.Items); } return this.Ok(searchResults); }
public IHttpActionResult Search([FromUri] ProductSearchRequest request) { request = request ?? new ProductSearchRequest(); request.Normalize(); var context = new Dictionary<string, object> { { "StoreId", request.Store }, }; var fullLoadedStore = GetStoreById(request.Store); if (fullLoadedStore == null) { throw new NullReferenceException(request.Store + " not found"); } var catalog = fullLoadedStore.Catalog; string categoryId = null; var criteria = new CatalogIndexedSearchCriteria { Locale = request.Language, Catalog = catalog.ToLowerInvariant(), IsFuzzySearch = true }; if (!string.IsNullOrWhiteSpace(request.Outline)) { criteria.Outlines.Add(string.Format("{0}/{1}*", catalog, request.Outline)); categoryId = request.Outline.Split(new[] { '/' }).Last(); context.Add("CategoryId", categoryId); } #region Filters // Now fill in filters var filters = _browseFilterService.GetFilters(context); // Add all filters foreach (var filter in filters) { criteria.Add(filter); } // apply terms var terms = ParseKeyValues(request.Terms); if (terms.Any()) { var filtersWithValues = filters .Where(x => (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase))) .Select(x => new { Filter = x, Values = x.GetValues() }) .ToList(); foreach (var term in terms) { var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase))); // handle special filter term with a key = "tags", it contains just values and we need to determine which filter to use if (filter == null && term.Key == "tags") { foreach (var termValue in term.Values) { // try to find filter by value var foundFilter = filtersWithValues.FirstOrDefault(x => x.Values.Any(y => y.Id.Equals(termValue))); if (foundFilter != null) { filter = foundFilter.Filter; var appliedFilter = _browseFilterService.Convert(filter, term.Values); criteria.Apply(appliedFilter); } } } else { var appliedFilter = _browseFilterService.Convert(filter, term.Values); criteria.Apply(appliedFilter); } } } #endregion #region Facets // apply facet filters var facets = ParseKeyValues(request.Facets); foreach (var facet in facets) { var filter = filters.SingleOrDefault( x => x.Key.Equals(facet.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(request.Currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, facet.Values); criteria.Apply(appliedFilter); } #endregion //criteria.ClassTypes.Add("Product"); criteria.RecordsToRetrieve = request.Take <= 0 ? 10 : request.Take; criteria.StartingRecord = request.Skip; criteria.Pricelists = request.Pricelists; criteria.Currency = request.Currency; criteria.StartDateFrom = request.StartDateFrom; criteria.SearchPhrase = request.SearchPhrase; #region sorting if (!string.IsNullOrEmpty(request.Sort)) { var isDescending = "desc".Equals(request.SortOrder, StringComparison.OrdinalIgnoreCase); SearchSort sortObject = null; switch (request.Sort.ToLowerInvariant()) { case "price": if (criteria.Pricelists != null) { sortObject = new SearchSort( criteria.Pricelists.Select( priceList => new SearchSortField(String.Format("price_{0}_{1}", criteria.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Format("sort{0}{1}", catalog, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(criteria.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(criteria.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } criteria.Sort = sortObject; } #endregion //Load ALL products var searchResults = _browseService.SearchItems(criteria, request.ResponseGroup); // populate inventory if ((request.ResponseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties) { PopulateInventory(fullLoadedStore.FulfillmentCenter, searchResults.Items); } return Ok(searchResults); }
public void Can_get_item_facets_lucene() { var scope = "default"; var queryBuilder = new LuceneSearchQueryBuilder(); var conn = new SearchConnection(_LuceneStorageDir, scope); var provider = new LuceneSearchProvider(queryBuilder, conn); Debug.WriteLine("Lucene connection: {0}", conn.ToString()); if (Directory.Exists(_LuceneStorageDir)) { Directory.Delete(_LuceneStorageDir, true); } SearchHelper.CreateSampleIndex(provider, scope); var criteria = new CatalogIndexedSearchCriteria { SearchPhrase = "", IsFuzzySearch = true, Catalog = "goods", RecordsToRetrieve = 10, StartingRecord = 0, Currency = "USD", Pricelists = new[] { "default" } }; var filter = new AttributeFilter { Key = "Color" }; filter.Values = new[] { new AttributeFilterValue { Id = "red", Value = "red" }, new AttributeFilterValue { Id = "blue", Value = "blue" }, new AttributeFilterValue { Id = "black", Value = "black" } }; var rangefilter = new RangeFilter { Key = "size" }; rangefilter.Values = new[] { new RangeFilterValue { Id = "0_to_5", Lower = "0", Upper = "5" }, new RangeFilterValue { Id = "5_to_10", Lower = "5", Upper = "10" } }; var priceRangefilter = new PriceRangeFilter { Currency = "usd" }; priceRangefilter.Values = new[] { new RangeFilterValue { Id = "0_to_100", Lower = "0", Upper = "100" }, new RangeFilterValue { Id = "100_to_700", Lower = "100", Upper = "700" } }; criteria.Add(filter); criteria.Add(rangefilter); criteria.Add(priceRangefilter); var results = provider.Search(scope, criteria); Assert.True(results.DocCount == 4, String.Format("Returns {0} instead of 4", results.DocCount)); var redCount = GetFacetCount(results, "Color", "red"); Assert.True(redCount == 2, String.Format("Returns {0} facets of red instead of 2", redCount)); var priceCount = GetFacetCount(results, "Price", "0_to_100"); Assert.True(priceCount == 2, String.Format("Returns {0} facets of 0_to_100 prices instead of 2", priceCount)); var priceCount2 = GetFacetCount(results, "Price", "100_to_700"); Assert.True(priceCount2 == 2, String.Format("Returns {0} facets of 100_to_700 prices instead of 2", priceCount2)); var sizeCount = GetFacetCount(results, "size", "0_to_5"); Assert.True(sizeCount == 2, String.Format("Returns {0} facets of 0_to_5 size instead of 2", sizeCount)); var sizeCount2 = GetFacetCount(results, "size", "5_to_10"); Assert.True(sizeCount2 == 1, String.Format("Returns {0} facets of 5_to_10 size instead of 1", sizeCount2)); // only 1 result because upper bound is not included var outlineCount = results.Documents[0].Documents[0]["__outline"].Values.Count(); Assert.True(outlineCount == 2, String.Format("Returns {0} outlines instead of 2", outlineCount)); Directory.Delete(_LuceneStorageDir, true); }
private SearchResult SearchProducts(SearchCriteria criteria) { var context = new Dictionary<string, object> { { "StoreId", criteria.StoreId }, }; var store = _storeService.GetById(criteria.StoreId); if (store == null) { throw new NullReferenceException("Cannot find store '" + criteria.StoreId + "'"); } var catalog = store.Catalog; var categoryId = criteria.CategoryId; var serviceCriteria = new CatalogIndexedSearchCriteria { Locale = criteria.LanguageCode, Catalog = catalog.ToLowerInvariant(), IsFuzzySearch = true, }; if (!string.IsNullOrWhiteSpace(criteria.Outline)) { serviceCriteria.Outlines.Add(string.Format(CultureInfo.InvariantCulture, "{0}/{1}*", catalog, criteria.Outline)); categoryId = criteria.Outline.Split('/').Last(); } else { if (!string.IsNullOrEmpty(categoryId)) { serviceCriteria.Outlines.Add(string.Format(CultureInfo.InvariantCulture, "{0}/{1}*", catalog, categoryId)); } } if (!string.IsNullOrEmpty(categoryId)) { context.Add("CategoryId", categoryId); } #region Filters // Now fill in filters var filters = _browseFilterService.GetFilters(context); // Add all filters foreach (var filter in filters) { serviceCriteria.Add(filter); } // apply terms var terms = ParseKeyValues(criteria.Terms); if (terms.Any()) { var filtersWithValues = filters .Where(x => (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(criteria.Currency, StringComparison.OrdinalIgnoreCase))) .Select(x => new { Filter = x, Values = x.GetValues() }) .ToList(); foreach (var term in terms) { var filter = filters.SingleOrDefault(x => x.Key.Equals(term.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(criteria.Currency, StringComparison.OrdinalIgnoreCase))); // handle special filter term with a key = "tags", it contains just values and we need to determine which filter to use if (filter == null && term.Key == "tags") { foreach (var termValue in term.Values) { // try to find filter by value var foundFilter = filtersWithValues.FirstOrDefault(x => x.Values.Any(y => y.Id.Equals(termValue))); if (foundFilter != null) { filter = foundFilter.Filter; var appliedFilter = _browseFilterService.Convert(filter, term.Values); serviceCriteria.Apply(appliedFilter); } } } else { var appliedFilter = _browseFilterService.Convert(filter, term.Values); serviceCriteria.Apply(appliedFilter); } } } #endregion #region Facets // apply facet filters var facets = ParseKeyValues(criteria.Facets); foreach (var facet in facets) { var filter = filters.SingleOrDefault( x => x.Key.Equals(facet.Key, StringComparison.OrdinalIgnoreCase) && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(criteria.Currency, StringComparison.OrdinalIgnoreCase))); var appliedFilter = _browseFilterService.Convert(filter, facet.Values); serviceCriteria.Apply(appliedFilter); } #endregion //criteria.ClassTypes.Add("Product"); serviceCriteria.RecordsToRetrieve = criteria.Take <= 0 ? 10 : criteria.Take; serviceCriteria.StartingRecord = criteria.Skip; serviceCriteria.Pricelists = criteria.PricelistIds; serviceCriteria.Currency = criteria.Currency; serviceCriteria.StartDateFrom = criteria.StartDateFrom; serviceCriteria.SearchPhrase = criteria.Keyword; #region sorting if (!string.IsNullOrEmpty(criteria.Sort)) { var isDescending = "desc".Equals(criteria.SortOrder, StringComparison.OrdinalIgnoreCase); SearchSort sortObject = null; switch (criteria.Sort.ToLowerInvariant()) { case "price": if (serviceCriteria.Pricelists != null) { sortObject = new SearchSort( serviceCriteria.Pricelists.Select( priceList => new SearchSortField(String.Format("price_{0}_{1}", serviceCriteria.Currency.ToLower(), priceList.ToLower())) { IgnoredUnmapped = true, IsDescending = isDescending, DataType = SearchSortField.DOUBLE }) .ToArray()); } break; case "position": sortObject = new SearchSort( new SearchSortField(string.Concat("sort", catalog, categoryId).ToLower()) { IgnoredUnmapped = true, IsDescending = isDescending }); break; case "name": sortObject = new SearchSort("name", isDescending); break; case "rating": sortObject = new SearchSort(serviceCriteria.ReviewsAverageField, isDescending); break; case "reviews": sortObject = new SearchSort(serviceCriteria.ReviewsTotalField, isDescending); break; default: sortObject = CatalogIndexedSearchCriteria.DefaultSortOrder; break; } serviceCriteria.Sort = sortObject; } #endregion var responseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Seo; if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { responseGroup |= ItemResponseGroup.ItemProperties; } if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations) { responseGroup |= ItemResponseGroup.Variations; } //Load ALL products var searchResults = _browseService.SearchItems(serviceCriteria, responseGroup); // populate inventory //if ((request.ResponseGroup & ItemResponseGroup.ItemProperties) == ItemResponseGroup.ItemProperties) if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties) { PopulateInventory(store.FulfillmentCenter, searchResults.Products); } return searchResults; }
public void Can_get_item_multiple_filters_lucene() { var scope = "default"; var queryBuilder = new LuceneSearchQueryBuilder(); var conn = new SearchConnection(_LuceneStorageDir, scope); var provider = new LuceneSearchProvider(queryBuilder, conn); Debug.WriteLine("Lucene connection: {0}", conn.ToString()); if (Directory.Exists(_LuceneStorageDir)) { Directory.Delete(_LuceneStorageDir, true); } SearchHelper.CreateSampleIndex(provider, scope); var criteria = new CatalogIndexedSearchCriteria { SearchPhrase = "", IsFuzzySearch = true, Catalog = "goods", RecordsToRetrieve = 10, StartingRecord = 0, Currency = "USD", Pricelists = new[] { "default" } }; var colorFilter = new AttributeFilter { Key = "Color" }; colorFilter.Values = new[] { new AttributeFilterValue { Id = "red", Value = "red" }, new AttributeFilterValue { Id = "blue", Value = "blue" }, new AttributeFilterValue { Id = "black", Value = "black" } }; var filter = new AttributeFilter { Key = "Color" }; filter.Values = new[] { new AttributeFilterValue { Id = "black", Value = "black" } }; var rangefilter = new RangeFilter { Key = "size" }; rangefilter.Values = new[] { new RangeFilterValue { Id = "0_to_5", Lower = "0", Upper = "5" }, new RangeFilterValue { Id = "5_to_10", Lower = "5", Upper = "11" } }; var priceRangefilter = new PriceRangeFilter { Currency = "usd" }; priceRangefilter.Values = new[] { new RangeFilterValue { Id = "100_to_700", Lower = "100", Upper = "700" } }; criteria.Add(colorFilter); criteria.Add(priceRangefilter); // add applied filters criteria.Apply(filter); //criteria.Apply(rangefilter); //criteria.Apply(priceRangefilter); var results = provider.Search(scope, criteria); var blackCount = GetFacetCount(results, "Color", "black"); Assert.True(blackCount == 1, String.Format("Returns {0} facets of black instead of 2", blackCount)); //Assert.True(results.DocCount == 1, String.Format("Returns {0} instead of 1", results.DocCount)); Directory.Delete(_LuceneStorageDir, true); }