private void BuildCategoryDetails(
            org.apache.lucene.facet.Facets facets, IList<CategoryDetail> categoryDetails, CategoryOptions categoryOptions, 
            string categoryName, string[] label, int count, IEnumerable<string> drillDownValues)
        {
            var lastLabel = label.Last();
            if (!drillDownValues.Contains(lastLabel))
            {
                categoryDetails.Add(new CategoryDetail { Value = lastLabel, Count = count });
//logger.Info("Value = {2} -- {0}; Count = {1}", lastLabel, count, String.Join("_ ", label));
            }
            else
            {
                var drilldownFacets = facets.getTopChildren(categoryOptions.MaxPerCategory, categoryName, label);
                if (drilldownFacets != null)
                {
                    var valDetail = new CategoryDetail { Value = lastLabel, Count = count };
                    categoryDetails.Add(valDetail);
                    foreach (var lv in drilldownFacets.labelValues)
                    {
                        var childLabel = new List<string>(label);
                        childLabel.Add(lv.label);
                        BuildCategoryDetails(
                            facets, valDetail.Children, categoryOptions, 
                            categoryName, childLabel.ToArray(), lv.value.intValue(), 
                            drillDownValues);
                    }
                }
            }
        }
        private IList<Category> RetrieveDrilldown(org.apache.lucene.facet.Facets facets, CategoryOptions categoryOptions)
        {
            var results = new List<Category>();

            foreach (var name in categoryOptions.FacetNames)
            {
                if (Facets.IsHierarchical(name))
                {
                    var topCategory = new Category { Field = name, IsHierarchical = true };
                    results.Add(topCategory);

                    var directChildFacets = facets.getTopChildren(categoryOptions.MaxPerCategory, name);
                    if (directChildFacets != null)
                    {
                        IEnumerable<string> drillDownValues = categoryOptions.GetCategoryValues(name);
                        foreach (var labelValue in directChildFacets.labelValues)
                        {
                            var labelName = new string[] { labelValue.label };
                            BuildCategoryDetails(
                                facets, topCategory.Details, categoryOptions, 
                                name, labelName, labelValue.value.intValue(), 
                                drillDownValues);
                        }
                    }
                }
                else
                {
                    var fp = facets.getTopChildren(categoryOptions.MaxPerCategory, name);
                    if (fp != null)
                    {
                        var list = new List<CategoryDetail>(fp.labelValues.Length);
                        foreach (var lv in fp.labelValues)
                        {
                            list.Add(new CategoryDetail { Value = lv.label, Count = lv.value.intValue() });
                        }
                        results.Add(new Category { Field = name, Details = list });
                    }
                }
            }
            return results;
        }
        public SearchModule() : base("/api")
        {
            Get["/search"] = p =>
            {
                string query = Request.Query.q.HasValue ? Request.Query.q : "";
                string properties = Request.Query.properties.HasValue ? Request.Query.properties : "";
                string sort = Request.Query.sort.HasValue ? Request.Query.sort : Searcher.SortType.ReverseDate.ToString();
                string firstStr = Request.Query.first.HasValue ? Request.Query.first : "";
                string countStr = Request.Query.count.HasValue ? Request.Query.count : "";
                string group = Request.Query.group.HasValue ? Request.Query.group : Searcher.GroupType.No.ToString();
                string maxPerCategoryString = Request.Query.max.HasValue ? Request.Query.max : "";
                string facetsString = Request.Query.categories.HasValue ? Request.Query.categories : "";
                string drillDownString = Request.Query.drilldown.HasValue ? Request.Query.drilldown : "";

                int first;
                if (!Int32.TryParse(firstStr, out first))
                {
                    first = 0;
                }

                int count;
                if (!Int32.TryParse(countStr, out count))
                {
                    count = 100;
                }

                var propertyList = properties.Split(',');
                var searchOptions = new SearchOptions
                {
                    Query = query,
                    Fields = propertyList,
                    PageIndex = first,
                    PageCount = count,
                    SortType = GetSortType(sort),
                    GroupType = GetGroupType(group)
                };

                int maxPerCategory;
                if (!Int32.TryParse(maxPerCategoryString, out maxPerCategory))
                {
                    maxPerCategory = 10;
                }

                var facetNames = new string[0];
                if (!String.IsNullOrWhiteSpace(facetsString))
                    facetNames = facetsString.Split(',');


                var categoryOptions = new CategoryOptions { FacetNames = facetNames, MaxPerCategory = maxPerCategory };

                // Drill down name and values are separated by ';' and the list is separated by ','. For hierarchical
                // drill downs/categories, levels in the hierarchy are separated by '_'
                //      Example: "placename:mexico_tulum,mexico_puerto morelos,canada;keywords:trip,flower"
                var drillDownValues = drillDownString.Split(';');
                foreach (var nameAndList in drillDownValues)
                {
                    var categoryAndValues = nameAndList.Split(':');
                    if (categoryAndValues.Length == 2)
                    {
                        var categoryName = categoryAndValues[0];
                        if (Facets.IsHierarchical(categoryName))
                        {
                            var valueList = categoryAndValues[1].Split(',');
                            foreach (var value in valueList)
                            {
                                var hierarchy = value.Split('_');
                                categoryOptions.Add(categoryName, hierarchy);
                            }
                        }
                        else
                        {
                            categoryOptions.Add(categoryName, categoryAndValues[1].Split(','));
                        }
                    }
                }

                var logTimer = Context.GetLogger();
                ApiSearchResult results = SearchFacade.Instance.Search(searchOptions, categoryOptions);

                logTimer.Set("resultCount", results.Groups.Sum(g => g.Images.Count));
                logTimer.Set("totalMatches", results.TotalMatches);
                return Response.AsJson(results);
            };
        }
 private DrillDownQuery ToQuery(SearchOptions searchOptions, CategoryOptions categoryOptions)
 {
     var query = new DrillDownQuery(Facets.FacetsConfig, ToQuery(searchOptions.Query));
     if (categoryOptions != null && categoryOptions.DrillDown.Any())
     {
         foreach (var kvp in categoryOptions.DrillDown)
             query.add(kvp.Key, kvp.Value.ToArray());
     }
     return query;
 }
        public SearchResult SearchForDocuments(SearchOptions searchOptions, CategoryOptions categoryOptions)
        {
            var query = ToQuery(searchOptions, categoryOptions);
logger.Info("Query: '{0}'", query);

            var searchResults = new SearchResult();
            searchResults.Matches = new List<MatchingDocument>(searchOptions.PageCount);
            if (CountOfIndexedFiles > 0)
            {
                using (var wrapper = mainSearchManager.Wrapper())
                {
                    DrillSideways ds = new DrillSideways(wrapper.IndexSearcher, Facets.FacetsConfig, GetTaxonomyReader());
                    var searchResult = ds.search(
                        query,
                        filter:null,
                        after:null,
                        topN:Math.Min(CountOfIndexedFiles, searchOptions.PageIndex + searchOptions.PageCount),
                        sort:new Sort(CreateSortField(searchOptions.SortType)),
                        doDocScores:false,
                        doMaxScore:false);

                    searchResults.TotalMatches = searchResult.hits.totalHits;
                    if (searchResults.TotalMatches > 0)
                    {
                        RetrieveMatches(wrapper, searchResult.hits, searchResults.Matches, searchOptions.DoesMatch, searchOptions.PageIndex, searchOptions.PageCount);
                    }

                    if (categoryOptions != null && categoryOptions.FacetNames != null && categoryOptions.MaxPerCategory > 0)
                    {
                        searchResults.Categories = RetrieveDrilldown(searchResult.facets, categoryOptions);
                    }
                }
            }

            return searchResults;
        }
        public dynamic Search(SearchOptions searchOptions, CategoryOptions categoryOptions)
        {
            var allGroups = new List<ApiGroupResult>();
            string lastGroup = null;
            var groupList = new List<Object>();

            searchOptions.DoesMatch = searchOptions.DoesMatch ?? DoesMatch;

            if (searchOptions.GroupType == Searcher.GroupType.No)
                allGroups.Add(new ApiGroupResult { Name = "All", Images = groupList });

            DateTime? oldestMatchDate = null;
            DateTime? newestMatchDate = null;

            var searchResults = Searcher.SearchForDocuments(searchOptions, categoryOptions);
            foreach (var match in searchResults.Matches)
            {
                if (searchOptions.GroupType == Searcher.GroupType.Yes)
                {
                    string currentGroup;
                    if (searchOptions.SortType == Searcher.SortType.Date || searchOptions.SortType == Searcher.SortType.ReverseDate)
                    {
                        currentGroup = match.CreatedDate.Value.ToString(ClientDateFormat);
                    }
                    else if (searchOptions.SortType == Searcher.SortType.Folder || searchOptions.SortType == Searcher.SortType.ReverseFolder)
                    {
                        // Strip off the filename, add part of the base folder
                        currentGroup = Path.Combine(
                            Searcher.ToBaseFolder(match.SignatureIndexPath).GetRightPathComponents(2),
                            Path.GetDirectoryName(Searcher.ToRelativePath(match.SignatureIndexPath).Substring(1)));
                    }
                    else
                        throw new NotImplementedException("Grouping for sorting: " + searchOptions.SortType);
                    
                    if (lastGroup == null || !lastGroup.Equals(currentGroup))
                    {
                        if (lastGroup != null)
                            groupList = new List<Object>();

                        allGroups.Add(new ApiGroupResult { Name = currentGroup, Images = groupList });
                        lastGroup = currentGroup;
                    }
                }

                groupList.Add(ToMatchingItem(match, searchOptions.Fields));

                if (!oldestMatchDate.HasValue)
                {
                    oldestMatchDate = newestMatchDate = match.CreatedDate;
                }
                else
                {
                    if (match.CreatedDate.HasValue)
                    {
                        DateTime matchDate = match.CreatedDate.Value;
                        if (matchDate > newestMatchDate.Value)
                            newestMatchDate = matchDate;
                        if (matchDate < oldestMatchDate.Value)
                            oldestMatchDate = matchDate;
                    }
                }
            }

            return new ApiSearchResult
            {
                TotalMatches = searchResults.TotalMatches,
                OldestPageDate = oldestMatchDate.HasValue ? oldestMatchDate.Value.ToString(ClientDateFormat) : "",
                NewestPageDate = newestMatchDate.HasValue ? newestMatchDate.Value.ToString(ClientDateFormat) : "",
                Groups = allGroups,
                Categories = searchResults.Categories
            };
        }