private void SearchCategories(SearchCriteria criteria, SearchResult result)
		{
			// TODO: optimize for performance, need to eliminate number of database queries
			// 1. Catalog should either be passed or loaded using caching
			// 2. Categories should be loaded by passing array of ids instead of parallel loading one by one
			using (var repository = _catalogRepositoryFactory())
			{
                var query = repository.Categories.Where(x => criteria.WithHidden ? true : x.IsActive);

                //Get list of search in categories
                var searchCategoryIds = criteria.CategoryIds;
                if (searchCategoryIds != null && searchCategoryIds.Any() && criteria.SearchInChildren)
                {
                    searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                }

                //Filter by keyword in all categories
                if (!string.IsNullOrEmpty(criteria.Keyword))
				{
					query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
				}
				else if (searchCategoryIds != null && searchCategoryIds.Any())
				{
                    if (criteria.HideDirectLinkedCategories)
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategory.ParentCategoryId)));
                    }
                    else
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategoryId)));
                    }
 				}
                else if (!string.IsNullOrEmpty(criteria.Code))
				{
					query = query.Where(x => x.Code == criteria.Code);
				}
                else if (criteria.CatalogIds != null)
                {
                    query = query.Where(x => (criteria.CatalogIds.Contains(x.CatalogId) && (x.ParentCategoryId == null || criteria.SearchInChildren)) || (x.OutgoingLinks.Any(y => y.TargetCategoryId == null && criteria.CatalogIds.Contains(y.TargetCatalogId))));

                }

                var categoryIds = query.Select(x => x.Id).ToArray();
                var categoryResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents;
                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
                {
                    categoryResponseGroup |= CategoryResponseGroup.WithProperties;
                }

                result.Categories = _categoryService.GetByIds(categoryIds, categoryResponseGroup)
                                                    .OrderByDescending(x => x.Priority)
                                                    .ThenBy(x => x.Name)
                                                    .ToList();
            
			}
		}
Ejemplo n.º 2
0
        public moduleModel.SearchResult SearchItems(CatalogIndexedSearchCriteria criteria, moduleModel.ItemResponseGroup responseGroup)
        {
            CatalogItemSearchResults results;
            var items = Search(criteria, out results, responseGroup);

            var response = new moduleModel.SearchResult();

            response.Products.AddRange(items);
            response.ProductsTotalCount = results.TotalCount;

            // TODO need better way to find applied filter values
            var appliedFilters = criteria.CurrentFilters.SelectMany(x => x.GetValues()).Select(x => x.Id).ToArray();
            if (results.FacetGroups != null)
            {
                response.Aggregations = results.FacetGroups.Select(g => g.ToModuleModel(appliedFilters)).ToArray();
            }
            return response;
        }
Ejemplo n.º 3
0
 private void SearchCatalogs(coreModel.SearchCriteria criteria, coreModel.SearchResult result)
 {
     using (var repository = _catalogRepositoryFactory())
     {
         var catalogIds      = repository.Catalogs.Select(x => x.Id).ToArray();
         var catalogs        = new ConcurrentBag <coreModel.Catalog>();
         var parallelOptions = new ParallelOptions
         {
             MaxDegreeOfParallelism = 10
         };
         Parallel.ForEach(catalogIds, parallelOptions, (x) =>
         {
             var catalog = _catalogService.GetById(x);
             catalogs.Add(catalog);
         });
         result.Catalogs = catalogs.OrderByDescending(x => x.Name).ToList();
     }
 }
Ejemplo n.º 4
0
        public moduleModel.SearchResult SearchItems(CatalogIndexedSearchCriteria criteria, moduleModel.ItemResponseGroup responseGroup)
        {
            CatalogItemSearchResults results;
            var items = Search(criteria, out results, responseGroup);

            var response = new moduleModel.SearchResult();

            response.Products.AddRange(items);
            response.ProductsTotalCount = results.TotalCount;

            // TODO need better way to find applied filter values
            var appliedFilters = criteria.CurrentFilters.SelectMany(x => x.GetValues()).Select(x => x.Id).ToArray();

            if (results.FacetGroups != null)
            {
                response.Aggregations = results.FacetGroups.Select(g => g.ToModuleModel(appliedFilters)).ToArray();
            }
            return(response);
        }
		public coreModel.SearchResult Search(coreModel.SearchCriteria criteria)
		{
			var retVal = new coreModel.SearchResult();
			var taskList = new List<Task>();

			if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProducts) == coreModel.ResponseGroup.WithProducts)
			{
				taskList.Add(Task.Factory.StartNew(() => SearchItems(criteria, retVal)));
			}
			if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCatalogs) == coreModel.ResponseGroup.WithCatalogs)
			{
				taskList.Add(Task.Factory.StartNew(() => SearchCatalogs(criteria, retVal)));
			}
			if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCategories) == coreModel.ResponseGroup.WithCategories)
			{
				taskList.Add(Task.Factory.StartNew(() => SearchCategories(criteria, retVal)));
			}
			Task.WaitAll(taskList.ToArray());

			return retVal;
		}
Ejemplo n.º 6
0
        public coreModel.SearchResult Search(coreModel.SearchCriteria criteria)
        {
            var retVal   = new coreModel.SearchResult();
            var taskList = new List <Task>();

            if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProducts) == coreModel.ResponseGroup.WithProducts)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchItems(criteria, retVal)));
            }
            if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCatalogs) == coreModel.ResponseGroup.WithCatalogs)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchCatalogs(criteria, retVal)));
            }
            if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithCategories) == coreModel.ResponseGroup.WithCategories)
            {
                taskList.Add(Task.Factory.StartNew(() => SearchCategories(criteria, retVal)));
            }
            Task.WaitAll(taskList.ToArray());

            return(retVal);
        }
        public static webModel.CatalogSearchResult ToWebModel(this coreModel.SearchResult result, IBlobUrlResolver blobUrlResolver)
        {
            var retVal = new webModel.CatalogSearchResult();

            retVal.InjectFrom(result);

            if (result.Products != null)
            {
                retVal.Products = result.Products.Select(x => x.ToWebModel(blobUrlResolver)).ToArray();
            }

            if (result.Categories != null)
            {
                retVal.Categories = result.Categories.Select(x => x.ToWebModel(blobUrlResolver)).ToArray();
            }

            if (result.Aggregations != null)
            {
                retVal.Aggregations = result.Aggregations.Select(a => a.ToWebModel()).ToArray();
            }

            return(retVal);
        }
        public static webModel.CatalogSearchResult ToWebModel(this coreModel.SearchResult result, IBlobUrlResolver blobUrlResolver)
        {
            var retVal = new webModel.CatalogSearchResult();

            retVal.ProductsTotalCount = result.ProductsTotalCount;

            if (result.Products != null)
            {
                //Parallel conversation for better performance
                var preservedOrder = result.Products.Select(x => x.Id).ToList();
                var productDtos    = new ConcurrentBag <CatalogModule.Web.Model.Product>();
                Parallel.ForEach(result.Products, (x) =>
                {
                    productDtos.Add(x.ToWebModel(blobUrlResolver));
                });
                retVal.Products = productDtos.OrderBy(i => preservedOrder.IndexOf(i.Id)).ToArray();
            }

            if (result.Categories != null)
            {
                var preservedOrder = result.Categories.Select(x => x.Id).ToList();
                var categoryDtos   = new ConcurrentBag <CatalogModule.Web.Model.Category>();
                Parallel.ForEach(result.Categories, (x) =>
                {
                    categoryDtos.Add(x.ToWebModel(blobUrlResolver));
                });
                retVal.Categories = categoryDtos.OrderBy(i => preservedOrder.IndexOf(i.Id)).ToArray();
            }

            if (result.Aggregations != null)
            {
                retVal.Aggregations = result.Aggregations.Select(a => a.ToWebModel()).ToArray();
            }

            return(retVal);
        }
Ejemplo n.º 9
0
        private void SearchCategories(coreModel.SearchCriteria criteria, coreModel.SearchResult result)
        {
            // TODO: optimize for performance, need to eliminate number of database queries
            // 1. Catalog should either be passed or loaded using caching
            // 2. Categories should be loaded by passing array of ids instead of parallel loading one by one
            using (var repository = _catalogRepositoryFactory())
            {
                var query = repository.Categories;

                dataModel.CatalogBase dbCatalog = null;
                var isVirtual = false;

                if (!String.IsNullOrEmpty(criteria.CatalogId))
                {
                    dbCatalog = repository.GetCatalogById(criteria.CatalogId);
                    isVirtual = dbCatalog is dataModel.VirtualCatalog;

                    query = query.Where(x => x.CatalogId == criteria.CatalogId);
                }

                if (!String.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
                }
                else if (!String.IsNullOrEmpty(criteria.CategoryId))
                {
                    if (isVirtual)
                    {
                        var dbCategory = repository.GetCategoryById(criteria.CategoryId);
                        //Need return all linked categories also
                        var allLinkedPhysicalCategoriesIds = dbCategory.IncommingLinks.Select(x => x.SourceCategoryId).ToArray();
                        query = repository.Categories;
                        if (allLinkedPhysicalCategoriesIds.Any())
                        {
                            if (criteria.HideDirectLinedCategories)
                            {
                                query = query.Where(x => x.ParentCategoryId == criteria.CategoryId || allLinkedPhysicalCategoriesIds.Contains(x.ParentCategoryId));
                            }
                            else
                            {
                                query = query.Where(x => x.ParentCategoryId == criteria.CategoryId || allLinkedPhysicalCategoriesIds.Contains(x.Id));
                            }
                        }
                        else
                        {
                            query = query.Where(x => x.ParentCategoryId == criteria.CategoryId);
                        }
                    }
                    else
                    {
                        query = query.Where(x => x.ParentCategoryId == criteria.CategoryId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }
                else if (!String.IsNullOrEmpty(criteria.SeoKeyword))
                {
                    var urlKeyword = _commerceService.GetSeoByKeyword(criteria.SeoKeyword).Where(x => x.ObjectType == typeof(coreModel.Category).Name).FirstOrDefault();
                    if (urlKeyword == null)
                    {
                        query = query.Where(x => false);
                    }
                    else
                    {
                        query = query.Where(x => x.Id == urlKeyword.ObjectId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.CatalogId))
                {
                    query = query.Where(x => x.CatalogId == criteria.CatalogId && (x.ParentCategoryId == null || criteria.GetAllCategories));
                    if (isVirtual)
                    {
                        //Need return only catalog linked categories
                        var allLinkedCategoriesIds = ((dataModel.VirtualCatalog)dbCatalog).IncommingLinks
                                                     .Where(x => x.TargetCategoryId == null)
                                                     .Select(x => x.SourceCategoryId);
                        //Search in all catalogs
                        query = repository.Categories;
                        query = query.Where(x => (x.CatalogId == criteria.CatalogId && (x.ParentCategoryId == null || criteria.GetAllCategories)) || allLinkedCategoriesIds.Contains(x.Id));
                    }
                }

                var categoryIds = query.Select(x => x.Id).ToArray();

                var categories      = new ConcurrentBag <coreModel.Category>();
                var parallelOptions = new ParallelOptions
                {
                    MaxDegreeOfParallelism = 10
                };
                Parallel.ForEach(categoryIds, parallelOptions, (x) =>
                {
                    var category = _categoryService.GetById(x);

                    categories.Add(category);
                });
                //Must order by priority
                result.Categories = categories.OrderByDescending(x => x.Priority).ThenBy(x => x.Name).ToList();
            }
        }
Ejemplo n.º 10
0
        private void SearchItems(coreModel.SearchCriteria criteria, coreModel.SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                var searchInAllCategories = criteria.GetAllCategories || !String.IsNullOrEmpty(criteria.Keyword);
                var isVirtual             = false;
                if (criteria.CatalogId != null)
                {
                    var dbCatalog = repository.GetCatalogById(criteria.CatalogId);
                    isVirtual = dbCatalog is dataModel.VirtualCatalog;
                }

                var query = repository.Items;
                if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithVariations) != coreModel.ResponseGroup.WithVariations)
                {
                    query = query.Where(x => x.ParentId == null);
                }


                if (!searchInAllCategories && !String.IsNullOrEmpty(criteria.CategoryId))
                {
                    if (isVirtual)
                    {
                        var dbCategory = repository.GetCategoryById(criteria.CategoryId);
                        ////Need return all items belongs to linked categories
                        //var allLinkedPhysicalCategoriesIds = dbCategory.IncommingLinks.Select(x => x.SourceCategoryId).ToArray();

                        query = query.Where(x => x.CategoryId == criteria.CategoryId || x.CategoryLinks.Any(c => c.CategoryId == criteria.CategoryId));
                    }
                    else
                    {
                        query = query.Where(x => x.CategoryId == criteria.CategoryId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.CatalogId))
                {
                    query = query.Where(x => x.CatalogId == criteria.CatalogId && (searchInAllCategories || x.CategoryId == null));
                }

                if (!String.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }
                else if (!String.IsNullOrEmpty(criteria.SeoKeyword))
                {
                    var urlKeyword = _commerceService.GetSeoByKeyword(criteria.SeoKeyword).Where(x => x.ObjectType == typeof(coreModel.CatalogProduct).Name).FirstOrDefault();
                    if (urlKeyword == null)
                    {
                        query = query.Where(x => false);
                    }
                    else
                    {
                        query = query.Where(x => x.Id == urlKeyword.ObjectId);
                    }
                }
                else if (!String.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
                }

                result.TotalCount = query.Count();

                var itemIds = query.OrderByDescending(x => x.Name)
                              .Skip(criteria.Start)
                              .Take(criteria.Count)
                              .Select(x => x.Id)
                              .ToArray();

                var productResponseGroup = coreModel.ItemResponseGroup.ItemInfo | coreModel.ItemResponseGroup.ItemAssets | ItemResponseGroup.Categories;
                if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithProperties) == coreModel.ResponseGroup.WithProperties)
                {
                    productResponseGroup |= coreModel.ItemResponseGroup.ItemProperties;
                }
                if ((criteria.ResponseGroup & coreModel.ResponseGroup.WithVariations) == coreModel.ResponseGroup.WithVariations)
                {
                    productResponseGroup |= coreModel.ItemResponseGroup.Variations;
                }

                var products = _itemService.GetByIds(itemIds, productResponseGroup);
                result.Products = products.OrderByDescending(x => x.Name).ToList();
            }
        }
        private void SearchCategories(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                var query = repository.Categories.Where(x => criteria.WithHidden || x.IsActive);

                //Get list of search in categories
                var searchCategoryIds = criteria.CategoryIds;

                if (!searchCategoryIds.IsNullOrEmpty())
                {
                    if (criteria.SearchInChildren)
                    {
                        searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                        //linked categories
                        var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray();
                    }

                    if (criteria.HideDirectLinkedCategories)
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategory.ParentCategoryId)));
                    }
                    else
                    {
                        query = query.Where(x => searchCategoryIds.Contains(x.ParentCategoryId) || x.OutgoingLinks.Any(y => searchCategoryIds.Contains(y.TargetCategoryId)));
                    }
                }
                else if (!criteria.CatalogIds.IsNullOrEmpty())
                {
                    if (criteria.SearchInChildren)
                    {
                        //need search in all catalog linked and children categories 
                        //First need load all categories belong to searched catalogs
                        searchCategoryIds = repository.Categories.Where(x => criteria.CatalogIds.Contains(x.CatalogId)).Select(x => x.Id).ToArray();
                        //Then load all physical categories linked to catalog
                        var allCatalogLinkedCategories = repository.CategoryLinks.Where(x => criteria.CatalogIds.Contains(x.TargetCatalogId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allCatalogLinkedCategories).Distinct().ToArray();
                        //Then expand all categories, get all children's
                        searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                        if (!searchCategoryIds.IsNullOrEmpty())
                        {
                            //find all categories belong searched catalogs and all categories direct or implicitly linked to catalogs
                            query = query.Where(x => searchCategoryIds.Contains(x.Id));
                        }
                    }
                    else
                    {
                        query = query.Where(x => (criteria.CatalogIds.Contains(x.CatalogId) && x.ParentCategoryId == null) || (x.OutgoingLinks.Any(y => y.TargetCategoryId == null && criteria.CatalogIds.Contains(y.TargetCatalogId))));
                    }
                }

                if (!string.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
                }
                else if (!string.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }

                var sortInfos = criteria.SortInfos;
                if (sortInfos.IsNullOrEmpty())
                {
                    sortInfos = new[] { new SortInfo { SortColumn = "Name" } };
                }
                //Try to replace sorting columns names
                TryTransformSortingInfoColumnNames(_categorySortingAliases, sortInfos);

                query = query.OrderBySortInfos(sortInfos);

                var categoryIds = query.Select(x => x.Id).ToArray();
                var categoryResponseGroup = CategoryResponseGroup.Info | CategoryResponseGroup.WithImages | CategoryResponseGroup.WithSeo | CategoryResponseGroup.WithLinks | CategoryResponseGroup.WithParents;

                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
                {
                    categoryResponseGroup |= CategoryResponseGroup.WithProperties;
                }

                if ((criteria.ResponseGroup & SearchResponseGroup.WithOutlines) == SearchResponseGroup.WithOutlines)
                {
                    categoryResponseGroup |= CategoryResponseGroup.WithOutlines;
                }

                result.Categories = _categoryService.GetByIds(categoryIds, categoryResponseGroup, criteria.CatalogId)
                                                    .AsQueryable()
                                                    .OrderBySortInfos(sortInfos)
                                                    .ToList();
            }
        }
        private void SearchItems(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                //list of search categories
                var searchCategoryIds = criteria.CategoryIds;
                if (criteria.SearchInChildren)
                {
                    if (!searchCategoryIds.IsNullOrEmpty())
                    {
                        searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                        //linked categories
                        var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray();
                    }
                    else if (!criteria.CatalogIds.IsNullOrEmpty())
                    {
                        //If category not specified need search in all linked and children categories
                        searchCategoryIds = repository.Categories.Where(x => criteria.CatalogIds.Contains(x.CatalogId)).Select(x => x.Id).ToArray();
                        var allCatalogLinkedCategories = repository.CategoryLinks.Where(x => criteria.CatalogIds.Contains(x.TargetCatalogId)).Select(x => x.SourceCategoryId).ToArray();
                        searchCategoryIds = searchCategoryIds.Concat(allCatalogLinkedCategories).Distinct().ToArray();
                    }
                }

                var query = repository.Items.Where(x => criteria.WithHidden || x.IsActive);

                if (!criteria.SearchInVariations)
                {
                    query = query.Where(x => x.ParentId == null);
                }

                if (!searchCategoryIds.IsNullOrEmpty())
                {
                    query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(c => searchCategoryIds.Contains(c.CategoryId)));
                }
                else if (!criteria.CatalogIds.IsNullOrEmpty())
                {
                    query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null));
                }

                if (!string.IsNullOrEmpty(criteria.Code))
                {
                    query = query.Where(x => x.Code == criteria.Code);
                }
                else if (!string.IsNullOrEmpty(criteria.Keyword))
                {
                    query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword) || x.ItemPropertyValues.Any(y => y.ShortTextValue == criteria.Keyword));
                }


                //Filter by property dictionary values
                if (!criteria.PropertyValues.IsNullOrEmpty())
                {
                    var propValueIds = criteria.PropertyValues.Select(x => x.ValueId).Distinct().ToArray();
                    query = query.Where(x => x.ItemPropertyValues.Any(y => propValueIds.Contains(y.KeyValue)));
                }

                if (!criteria.ProductTypes.IsNullOrEmpty())
                {
                    query = query.Where(x => criteria.ProductTypes.Contains(x.ProductType));
                }

                if (criteria.OnlyBuyable != null)
                {
                    query = query.Where(x => x.IsBuyable == criteria.OnlyBuyable);
                }

                if (criteria.OnlyWithTrackingInventory != null)
                {
                    query = query.Where(x => x.TrackInventory == criteria.OnlyWithTrackingInventory);
                }

                result.ProductsTotalCount = query.Count();

                var sortInfos = criteria.SortInfos;
                if (sortInfos.IsNullOrEmpty())
                {
                    sortInfos = new[] { new SortInfo { SortColumn = "Name" } };
                }
                //Try to replace sorting columns names
                TryTransformSortingInfoColumnNames(_productSortingAliases, sortInfos);

                query = query.OrderBySortInfos(sortInfos);

                var itemIds = query.Skip(criteria.Skip)
                                   .Take(criteria.Take)
                                   .Select(x => x.Id)
                                   .ToArray();

                var productResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo;

                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
                {
                    productResponseGroup |= ItemResponseGroup.ItemProperties;
                }

                if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations)
                {
                    productResponseGroup |= ItemResponseGroup.Variations;
                }

                if ((criteria.ResponseGroup & SearchResponseGroup.WithOutlines) == SearchResponseGroup.WithOutlines)
                {
                    productResponseGroup |= ItemResponseGroup.Outlines;
                }

                var products = _itemService.GetByIds(itemIds, productResponseGroup, criteria.CatalogId);
                result.Products = products.AsQueryable().OrderBySortInfos(sortInfos).ToList();
            }

        }
        private void SearchCatalogs(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                var catalogIds = criteria.CatalogIds;
                if (catalogIds.IsNullOrEmpty())
                {
                    catalogIds = repository.Catalogs.Select(x => x.Id).ToArray();
                }

                var catalogs = new ConcurrentBag<Catalog>();
                var parallelOptions = new ParallelOptions
                {
                    MaxDegreeOfParallelism = 10
                };

                Parallel.ForEach(catalogIds, parallelOptions, catalogId =>
                {
                    var catalog = _catalogService.GetById(catalogId);
                    catalogs.Add(catalog);
                });

                result.Catalogs = catalogs.OrderByDescending(x => x.Name).ToList();
            }
        }
        private void SearchItems(SearchCriteria criteria, SearchResult result)
        {
            using (var repository = _catalogRepositoryFactory())
            {
                //list of search categories
                var searchCategoryIds = criteria.CategoryIds;
                if (searchCategoryIds != null && criteria.SearchInChildren)
                {
                    searchCategoryIds = searchCategoryIds.Concat(repository.GetAllChildrenCategoriesIds(searchCategoryIds)).ToArray();
                    //linked categories
                    var allLinkedCategories = repository.CategoryLinks.Where(x => searchCategoryIds.Contains(x.TargetCategoryId)).Select(x => x.SourceCategoryId).ToArray();
                    searchCategoryIds = searchCategoryIds.Concat(allLinkedCategories).Distinct().ToArray();
                }

                //Do not search in variations
                var query = repository.Items.Where(x => x.ParentId == null).Where(x => criteria.WithHidden ? true : x.IsActive);

                if (searchCategoryIds != null)
                {
                   query = query.Where(x => searchCategoryIds.Contains(x.CategoryId) || x.CategoryLinks.Any(c => searchCategoryIds.Contains(c.CategoryId)));
                }
				else if (criteria.CatalogIds != null)
				{
					query = query.Where(x => criteria.CatalogIds.Contains(x.CatalogId) && (criteria.SearchInChildren || x.CategoryId == null));
				}

                if (!string.IsNullOrEmpty(criteria.Code))
				{
					query = query.Where(x => x.Code == criteria.Code);
				}
                else if (!string.IsNullOrEmpty(criteria.Keyword))
				{
					query = query.Where(x => x.Name.Contains(criteria.Keyword) || x.Code.Contains(criteria.Keyword));
				}

                //Filter by property  dictionary values
                if (criteria.PropertyValues != null && criteria.PropertyValues.Any())
                {
                    var propValueIds = criteria.PropertyValues.Select(x => x.ValueId).Distinct().ToArray();
                    query = query.Where(x => x.ItemPropertyValues.Any(y => propValueIds.Contains(y.KeyValue)));
                }

                result.ProductsTotalCount = query.Count();

                var itemIds = query.OrderByDescending(x => x.Name)
                                   .Skip(criteria.Skip)
                                   .Take(criteria.Take)
                                   .Select(x => x.Id)
                                   .ToArray();

                var productResponseGroup = ItemResponseGroup.ItemInfo | ItemResponseGroup.ItemAssets | ItemResponseGroup.Links | ItemResponseGroup.Seo;

                if ((criteria.ResponseGroup & SearchResponseGroup.WithProperties) == SearchResponseGroup.WithProperties)
				{
                    productResponseGroup |= ItemResponseGroup.ItemProperties;
				}

                if ((criteria.ResponseGroup & SearchResponseGroup.WithVariations) == SearchResponseGroup.WithVariations)
				{
                    productResponseGroup |= ItemResponseGroup.Variations;
				}

				var products = _itemService.GetByIds(itemIds, productResponseGroup);
                result.Products = products.OrderByDescending(x => x.Name).ToList();
            }
        }