コード例 #1
0
        private string[] QueryOverMultipleWords(SuggestionQueryServerSide parameters, string queryText)
        {
            parameters.Popularity = false;
            var individualTerms = queryText.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);

            var result = new HashSet <string>();

            var currentMaxSuggestions = parameters.MaxSuggestions;

            foreach (var term in individualTerms)
            {
                if (currentMaxSuggestions <= 0)
                {
                    break;
                }

                foreach (var suggestion in QueryOverSingleWord(parameters, term))
                {
                    if (result.Add(suggestion) == false)
                    {
                        continue;
                    }

                    currentMaxSuggestions--;
                    if (currentMaxSuggestions <= 0)
                    {
                        break;
                    }
                }
            }

            return(result.ToArray());
        }
コード例 #2
0
        private SuggestionQueryServerSide GetSuggestionQuery(JsonOperationContext context, HttpMethod method)
        {
            if (method == HttpMethod.Get)
            {
                throw new NotImplementedException("RavenDB-8882");
            }

            var indexQueryJson = context.ReadForMemory(RequestBodyStream(), "suggestion/query");

            // read from cache here

            return(SuggestionQueryServerSide.Create(indexQueryJson));
        }
コード例 #3
0
        private SuggestionQueryServerSide GetSuggestionQuery(JsonOperationContext context, HttpMethod method)
        {
            if (method == HttpMethod.Get)
            {
                //MoreLikeThisQueryServerSide.Create(HttpContext, GetPageSize(), context);
                throw new NotImplementedException();
            }

            var indexQueryJson = context.ReadForMemory(RequestBodyStream(), "suggestion/query");

            // read from cache here

            return(SuggestionQueryServerSide.Create(indexQueryJson));
        }
コード例 #4
0
        public string[] Suggestions(SuggestionQueryServerSide query, CancellationToken token)
        {
            var term = query.Term;

            if (term.StartsWith("<<") && term.EndsWith(">>"))
            {
                return(QueryOverMultipleWords(query, term.Substring(2, term.Length - 4)));
            }
            if (term.StartsWith("(") && term.EndsWith(")"))
            {
                return(QueryOverMultipleWords(query, term.Substring(1, term.Length - 2)));
            }

            return(QueryOverSingleWord(query, term));
        }
コード例 #5
0
        private string[] QueryOverSingleWord(SuggestionQueryServerSide parameters, string word)
        {
            // Perform devirtualization of the distance function when supported.
            switch (parameters.Distance)
            {
            case StringDistanceTypes.JaroWinkler:
                return(QueryOverSingleWord(parameters, word, new JaroWinklerDistance()));

            case StringDistanceTypes.NGram:
                return(QueryOverSingleWord(parameters, word, new NGramDistance()));

            case StringDistanceTypes.Default:
            case StringDistanceTypes.Levenshtein:
            default:
                return(QueryOverSingleWord(parameters, word, new LevenshteinDistance()));
            }
        }
コード例 #6
0
        public SuggestionQueryResultServerSide ExecuteSuggestionQuery(SuggestionQueryServerSide query, DocumentsOperationContext context, long?existingResultEtag, OperationCancelToken token)
        {
            if (query == null)
            {
                throw new ArgumentNullException(nameof(query));
            }

            // Check pre-requisites for the query to happen.

            if (string.IsNullOrWhiteSpace(query.Term))
            {
                throw new InvalidOperationException("Suggestions queries require a term.");
            }

            if (string.IsNullOrWhiteSpace(query.Field))
            {
                throw new InvalidOperationException("Suggestions queries require a field.");
            }

            var sw = Stopwatch.StartNew();

            // Check definition for the index.

            var index           = GetIndex(query.IndexName);
            var indexDefinition = index.GetIndexDefinition();

            if (indexDefinition == null)
            {
                throw new InvalidOperationException($"Could not find specified index '{this}'.");
            }

            if (indexDefinition.Fields.TryGetValue(query.Field, out IndexFieldOptions field) == false)
            {
                throw new InvalidOperationException($"Index '{this}' does not have a field '{query.Field}'.");
            }

            if (field.Suggestions == null)
            {
                throw new InvalidOperationException($"Index '{this}' does not have suggestions configured for field '{query.Field}'.");
            }

            if (field.Suggestions.Value == false)
            {
                throw new InvalidOperationException($"Index '{this}' have suggestions explicitly disabled for field '{query.Field}'.");
            }

            if (existingResultEtag.HasValue)
            {
                var etag = index.GetIndexEtag();
                if (etag == existingResultEtag.Value)
                {
                    return(SuggestionQueryResultServerSide.NotModifiedResult);
                }
            }

            context.OpenReadTransaction();

            var result = index.SuggestionsQuery(query, context, token);

            result.DurationInMs = (int)sw.Elapsed.TotalMilliseconds;
            return(result);
        }
コード例 #7
0
        private string[] QueryOverSingleWord <TDistance>(SuggestionQueryServerSide parameters, string word, TDistance sd)
            where TDistance : IStringDistance
        {
            float  min         = parameters.Accuracy.Value;
            string field       = parameters.Field;
            int    numSug      = parameters.MaxSuggestions;
            bool   morePopular = parameters.Popularity;

            int lengthWord = word.Length;

            var ir = _searcher.IndexReader;

            int freq     = (ir != null && field != null) ? ir.DocFreq(new Term(FWord, word), _state) : 0;
            int goalFreq = (morePopular && ir != null && field != null) ? freq : 0;

            // if the word exists in the real index and we don't care for word frequency, return the word itself
            if (!morePopular && freq > 0)
            {
                return(new[] { word });
            }

            var query = new BooleanQuery();

            var alreadySeen = new HashSet <string>();

            int ng  = GetMin(lengthWord);
            int max = ng + 1;

            var table = GramsTable;

            for (; ng <= max; ng++)
            {
                string[] grams = FormGrams(word, ng);

                if (grams.Length == 0)
                {
                    continue; // hmm
                }

                if (BoostStart > 0)
                {
                    // should we boost prefixes?
                    Add(query, table[ng].Start, grams[0], BoostStart); // matches start of word
                }

                if (BoostEnd > 0)
                {
                    // should we boost suffixes
                    Add(query, table[ng].End, grams[grams.Length - 1], BoostEnd); // matches end of word
                }

                for (int i = 0; i < grams.Length; i++)
                {
                    Add(query, table[ng].Gram, grams[i]);
                }
            }

            int maxHits = 10 * numSug;

            //    System.out.println("Q: " + query);
            ScoreDoc[] hits = _searcher.Search(query, null, maxHits, _state).ScoreDocs;

            //    System.out.println("HITS: " + hits.length());
            var queue = new SuggestWordQueue(numSug);

            // go thru more than 'maxr' matches in case the distance filter triggers
            int stop = Math.Min(hits.Length, maxHits);

            var suggestedWord = new SuggestWord();

            for (int i = 0; i < stop; i++)
            {
                suggestedWord.Term = _searcher.Doc(hits[i].Doc, _state).Get(FWord, _state); // get orig word

                // don't suggest a word for itself, that would be silly
                if (suggestedWord.Term.Equals(word, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                // edit distance
                suggestedWord.Score = sd.GetDistance(word, suggestedWord.Term);
                if (suggestedWord.Score < min)
                {
                    continue;
                }

                if (ir != null && field != null)
                {
                    // use the user index
                    suggestedWord.Freq = _searcher.DocFreq(new Term(FWord, suggestedWord.Term), _state); // freq in the index

                    // don't suggest a word that is not present in the field
                    if ((morePopular && goalFreq > suggestedWord.Freq) || suggestedWord.Freq < 1)
                    {
                        continue;
                    }
                }

                if (alreadySeen.Add(suggestedWord.Term) == false) // we already seen this word, no point returning it twice
                {
                    continue;
                }

                queue.InsertWithOverflow(suggestedWord);
                if (queue.Size() == numSug)
                {
                    // if queue full, maintain the minScore score
                    min = queue.Top().Score;
                }

                suggestedWord = new SuggestWord();
            }

            int size = queue.Size();

            if (size == 0)
            {
                return(EmptyArray);
            }

            // convert to array string
            string[] list = new string[size];
            for (int i = size - 1; i >= 0; i--)
            {
                list[i] = queue.Pop().Term;
            }

            return(list);
        }