Ejemplo n.º 1
0
        private static Query ParseQuery(SearchFilter searchFilter)
        {
            // 1. parse the query into field clauses and general terms
            // We imagine that mostly, field clauses are meant to 'filter' results found searching for general terms.
            // The resulting clause collections may be empty.
            var queryParser        = new NuGetQueryParser();
            var clauses            = queryParser.Parse(searchFilter.SearchTerm).Select(StandardizeSearchTerms).ToList();
            var fieldSpecificTerms = clauses.Where(a => a.Field != null);
            var generalTerms       = clauses.Where(a => a.Field == null);

            // Convert terms to appropriate Lucene Query objects
            var analyzer             = new PerFieldAnalyzer();
            var fieldSpecificQueries = fieldSpecificTerms
                                       .Select(c => AnalysisHelper.GetFieldQuery(analyzer, c.Field, c.TermOrPhrase))
                                       .Where(q => !IsDegenerateQuery(q))
                                       .ToList();

            var generalQueries = generalTerms
                                 .Select(c => AnalysisHelper.GetMultiFieldQuery(analyzer, Fields, c.TermOrPhrase))
                                 .Where(q => !IsDegenerateQuery(q))
                                 .ToList();

            if (fieldSpecificQueries.Count == 0 &&
                generalQueries.Count == 0)
            {
                return(new MatchAllDocsQuery());
            }

            // At this point we try to detect user intent...
            // a) General search? [foo bar]
            // b) Id-targeted search? [id:Foo bar]
            // c)  Other Field-targeted search? [author:Foo bar]
            bool  doExactId    = !fieldSpecificQueries.Any();
            Query generalQuery = BuildGeneralQuery(doExactId, searchFilter.SearchTerm, analyzer, generalTerms, generalQueries);

            // IF  field targeting is done, we should basically want to AND their field specific queries with all other query terms
            if (fieldSpecificQueries.Any())
            {
                var combinedQuery = new BooleanQuery();

                if (!IsDegenerateQuery(generalQuery))
                {
                    combinedQuery.Add(generalQuery, Occur.MUST);
                }

                foreach (var fieldQuery in fieldSpecificQueries)
                {
                    if (!IsDegenerateQuery(fieldQuery))
                    {
                        combinedQuery.Add(fieldQuery, Occur.MUST);
                    }
                }

                generalQuery = combinedQuery;
            }

            return(generalQuery);
        }
Ejemplo n.º 2
0
        private static Query BuildGeneralQuery(
            bool doExactId,
            string originalSearchText,
            Analyzer analyzer,
            IEnumerable <NuGetSearchTerm> generalTerms,
            IEnumerable <Query> generalQueries)
        {
            // All terms in the multi-term query appear in at least one of the target fields.
            var conjuctionQuery = new BooleanQuery();

            conjuctionQuery.Boost = 2.0f;

            // Some terms in the multi-term query appear in at least one of the target fields.
            var disjunctionQuery = new BooleanQuery();

            disjunctionQuery.Boost = 0.1f;

            // Suffix wildcard search e.g. jquer*
            var wildCardQuery = new BooleanQuery();

            wildCardQuery.Boost = 0.5f;

            string escapedExactId = originalSearchText.ToLowerInvariant();

            Query exactIdQuery    = null;
            Query wildCardIdQuery = null;

            if (doExactId)
            {
                exactIdQuery       = new TermQuery(new Term("Id-Exact", escapedExactId));
                exactIdQuery.Boost = 7.5f;

                wildCardIdQuery = new WildcardQuery(new Term("Id-Exact", "*" + escapedExactId + "*"));
            }

            Query nearlyExactIdQuery = null;

            if (generalTerms.Any())
            {
                string escapedApproximateId = string.Join(" ", generalTerms.Select(c => c.TermOrPhrase));
                nearlyExactIdQuery       = AnalysisHelper.GetFieldQuery(analyzer, "Id", escapedApproximateId);
                nearlyExactIdQuery.Boost = 2.0f;
            }

            foreach (var termQuery in generalQueries)
            {
                conjuctionQuery.Add(termQuery, Occur.MUST);
                disjunctionQuery.Add(termQuery, Occur.SHOULD);
            }

            var sanitizedTerms = generalTerms.Select(c => c.TermOrPhrase.ToLowerInvariant());

            foreach (var sanitizedTerm in sanitizedTerms)
            {
                foreach (var field in Fields)
                {
                    var wildCardTermQuery = new WildcardQuery(new Term(field, sanitizedTerm + "*"));
                    wildCardTermQuery.Boost = 0.7f;
                    wildCardQuery.Add(wildCardTermQuery, Occur.SHOULD);
                }
            }

            // OR of all the applicable queries
            var queries = new Query[]
            {
                exactIdQuery, wildCardIdQuery, nearlyExactIdQuery, conjuctionQuery, disjunctionQuery, wildCardQuery
            };

            var queriesToCombine = queries.Where(q => !IsDegenerateQuery(q));
            var query            = conjuctionQuery.Combine(queriesToCombine.ToArray());

            return(query);
        }