Search in sources :

Example 1 with Suggestion

use of org.opensearch.search.suggest.Suggest.Suggestion in project OpenSearch by opensearch-project.

the class SuggestionTests method doTestFromXContent.

@SuppressWarnings({ "rawtypes" })
private void doTestFromXContent(boolean addRandomFields) throws IOException {
    ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
    for (Class<Suggestion<? extends Entry<? extends Option>>> type : SUGGESTION_TYPES) {
        Suggestion suggestion = createTestItem(type);
        XContentType xContentType = randomFrom(XContentType.values());
        boolean humanReadable = randomBoolean();
        BytesReference originalBytes = toShuffledXContent(suggestion, xContentType, params, humanReadable);
        BytesReference mutated;
        if (addRandomFields) {
            // - "contexts" is an object consisting of key/array pairs, we shouldn't add anything random there
            // - there can be inner search hits fields inside this option where we cannot add random stuff
            // - the root object should be excluded since it contains the named suggestion arrays
            // We also exclude options that contain SearchHits, as all unknown fields
            // on a root level of SearchHit are interpreted as meta-fields and will be kept.
            Predicate<String> excludeFilter = path -> path.isEmpty() || path.endsWith(CompletionSuggestion.Entry.Option.CONTEXTS.getPreferredName()) || path.endsWith("highlight") || path.contains("fields") || path.contains("_source") || path.contains("inner_hits") || path.contains("options");
            mutated = insertRandomFields(xContentType, originalBytes, excludeFilter, random());
        } else {
            mutated = originalBytes;
        }
        Suggestion parsed;
        try (XContentParser parser = createParser(xContentType.xContent(), mutated)) {
            ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
            ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser);
            ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.nextToken(), parser);
            parsed = Suggestion.fromXContent(parser);
            assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
            assertNull(parser.nextToken());
        }
        assertEquals(suggestion.getName(), parsed.getName());
        assertEquals(suggestion.getEntries().size(), parsed.getEntries().size());
        // We don't parse size via xContent, instead we set it to -1 on the client side
        assertEquals(-1, parsed.getSize());
        assertToXContentEquivalent(originalBytes, toXContent(parsed, xContentType, params, humanReadable), xContentType);
    }
}
Also used : ToXContent(org.opensearch.common.xcontent.ToXContent) BytesReference(org.opensearch.common.bytes.BytesReference) TermSuggestion(org.opensearch.search.suggest.term.TermSuggestion) OpenSearchAssertions.assertToXContentEquivalent(org.opensearch.test.hamcrest.OpenSearchAssertions.assertToXContentEquivalent) BytesReference(org.opensearch.common.bytes.BytesReference) XContentTestUtils.insertRandomFields(org.opensearch.test.XContentTestUtils.insertRandomFields) ToXContent(org.opensearch.common.xcontent.ToXContent) Entry(org.opensearch.search.suggest.Suggest.Suggestion.Entry) Suggestion(org.opensearch.search.suggest.Suggest.Suggestion) Supplier(java.util.function.Supplier) XContentParser(org.opensearch.common.xcontent.XContentParser) RestSearchAction(org.opensearch.rest.action.search.RestSearchAction) XContentHelper.toXContent(org.opensearch.common.xcontent.XContentHelper.toXContent) NamedObjectNotFoundException(org.opensearch.common.xcontent.NamedObjectNotFoundException) Map(java.util.Map) Predicate(java.util.function.Predicate) OpenSearchTestCase(org.opensearch.test.OpenSearchTestCase) Set(java.util.Set) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) IOException(java.io.IOException) XContentParserUtils.ensureExpectedToken(org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken) PhraseSuggestion(org.opensearch.search.suggest.phrase.PhraseSuggestion) XContent(org.opensearch.common.xcontent.XContent) Option(org.opensearch.search.suggest.Suggest.Suggestion.Entry.Option) NamedXContentRegistry(org.opensearch.common.xcontent.NamedXContentRegistry) JsonXContent(org.opensearch.common.xcontent.json.JsonXContent) XContentType(org.opensearch.common.xcontent.XContentType) DeprecationHandler(org.opensearch.common.xcontent.DeprecationHandler) Collections(java.util.Collections) Text(org.opensearch.common.text.Text) TermSuggestion(org.opensearch.search.suggest.term.TermSuggestion) Suggestion(org.opensearch.search.suggest.Suggest.Suggestion) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) PhraseSuggestion(org.opensearch.search.suggest.phrase.PhraseSuggestion) Entry(org.opensearch.search.suggest.Suggest.Suggestion.Entry) XContentType(org.opensearch.common.xcontent.XContentType) Option(org.opensearch.search.suggest.Suggest.Suggestion.Entry.Option) XContentParser(org.opensearch.common.xcontent.XContentParser)

Example 2 with Suggestion

use of org.opensearch.search.suggest.Suggest.Suggestion in project OpenSearch by opensearch-project.

the class SuggestionTests method createTestItem.

@SuppressWarnings({ "unchecked", "rawtypes" })
public static Suggestion<? extends Entry<? extends Option>> createTestItem(Class<? extends Suggestion> type) {
    String name = randomAlphaOfLengthBetween(5, 10);
    // note: size will not be rendered via "toXContent", only passed on internally on transport layer
    int size = randomInt();
    Supplier<Entry> entrySupplier;
    Suggestion suggestion;
    if (type == TermSuggestion.class) {
        suggestion = new TermSuggestion(name, size, randomFrom(SortBy.values()));
        entrySupplier = () -> SuggestionEntryTests.createTestItem(TermSuggestion.Entry.class);
    } else if (type == PhraseSuggestion.class) {
        suggestion = new PhraseSuggestion(name, size);
        entrySupplier = () -> SuggestionEntryTests.createTestItem(PhraseSuggestion.Entry.class);
    } else if (type == CompletionSuggestion.class) {
        suggestion = new CompletionSuggestion(name, size, randomBoolean());
        entrySupplier = () -> SuggestionEntryTests.createTestItem(CompletionSuggestion.Entry.class);
    } else {
        throw new UnsupportedOperationException("type not supported [" + type + "]");
    }
    int numEntries;
    if (frequently()) {
        if (type == CompletionSuggestion.class) {
            // CompletionSuggestion can have max. one entry
            numEntries = 1;
        } else {
            numEntries = randomIntBetween(1, 5);
        }
    } else {
        // also occasionally test zero entries
        numEntries = 0;
    }
    for (int i = 0; i < numEntries; i++) {
        suggestion.addTerm(entrySupplier.get());
    }
    return suggestion;
}
Also used : TermSuggestion(org.opensearch.search.suggest.term.TermSuggestion) Suggestion(org.opensearch.search.suggest.Suggest.Suggestion) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) PhraseSuggestion(org.opensearch.search.suggest.phrase.PhraseSuggestion) Entry(org.opensearch.search.suggest.Suggest.Suggestion.Entry) PhraseSuggestion(org.opensearch.search.suggest.phrase.PhraseSuggestion) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) TermSuggestion(org.opensearch.search.suggest.term.TermSuggestion)

Example 3 with Suggestion

use of org.opensearch.search.suggest.Suggest.Suggestion in project OpenSearch by opensearch-project.

the class SuggestTests method testFromXContent.

public void testFromXContent() throws IOException {
    ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(RestSearchAction.TYPED_KEYS_PARAM, "true"));
    Suggest suggest = createTestItem();
    XContentType xContentType = randomFrom(XContentType.values());
    boolean humanReadable = randomBoolean();
    BytesReference originalBytes = toShuffledXContent(suggest, xContentType, params, humanReadable);
    Suggest parsed;
    try (XContentParser parser = createParser(xContentType.xContent(), originalBytes)) {
        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
        ensureFieldName(parser, parser.nextToken(), Suggest.NAME);
        ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser);
        parsed = Suggest.fromXContent(parser);
        assertEquals(XContentParser.Token.END_OBJECT, parser.currentToken());
        assertEquals(XContentParser.Token.END_OBJECT, parser.nextToken());
        assertNull(parser.nextToken());
    }
    assertEquals(suggest.size(), parsed.size());
    for (Suggestion suggestion : suggest) {
        Suggestion<? extends Entry<? extends Option>> parsedSuggestion = parsed.getSuggestion(suggestion.getName());
        assertNotNull(parsedSuggestion);
        assertEquals(suggestion.getClass(), parsedSuggestion.getClass());
    }
    assertToXContentEquivalent(originalBytes, toXContent(parsed, xContentType, params, humanReadable), xContentType);
}
Also used : ToXContent(org.opensearch.common.xcontent.ToXContent) BytesReference(org.opensearch.common.bytes.BytesReference) TermSuggestion(org.opensearch.search.suggest.term.TermSuggestion) Suggestion(org.opensearch.search.suggest.Suggest.Suggestion) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) PhraseSuggestion(org.opensearch.search.suggest.phrase.PhraseSuggestion) XContentType(org.opensearch.common.xcontent.XContentType) XContentParser(org.opensearch.common.xcontent.XContentParser)

Example 4 with Suggestion

use of org.opensearch.search.suggest.Suggest.Suggestion in project OpenSearch by opensearch-project.

the class SearchPhaseController method reducedQueryPhase.

/**
 * Reduces the given query results and consumes all aggregations and profile results.
 * @param queryResults a list of non-null query shard results
 * @param bufferedAggs a list of pre-collected aggregations.
 * @param bufferedTopDocs a list of pre-collected top docs.
 * @param numReducePhases the number of non-final reduce phases applied to the query results.
 * @see QuerySearchResult#consumeAggs()
 * @see QuerySearchResult#consumeProfileResult()
 */
ReducedQueryPhase reducedQueryPhase(Collection<? extends SearchPhaseResult> queryResults, List<InternalAggregations> bufferedAggs, List<TopDocs> bufferedTopDocs, TopDocsStats topDocsStats, int numReducePhases, boolean isScrollRequest, InternalAggregation.ReduceContextBuilder aggReduceContextBuilder, boolean performFinalReduce) {
    assert numReducePhases >= 0 : "num reduce phases must be >= 0 but was: " + numReducePhases;
    // increment for this phase
    numReducePhases++;
    if (queryResults.isEmpty()) {
        // early terminate we have nothing to reduce
        final TotalHits totalHits = topDocsStats.getTotalHits();
        return new ReducedQueryPhase(totalHits, topDocsStats.fetchHits, topDocsStats.getMaxScore(), false, null, null, null, null, SortedTopDocs.EMPTY, null, numReducePhases, 0, 0, true);
    }
    int total = queryResults.size();
    queryResults = queryResults.stream().filter(res -> res.queryResult().isNull() == false).collect(Collectors.toList());
    String errorMsg = "must have at least one non-empty search result, got 0 out of " + total;
    assert queryResults.isEmpty() == false : errorMsg;
    if (queryResults.isEmpty()) {
        throw new IllegalStateException(errorMsg);
    }
    validateMergeSortValueFormats(queryResults);
    final QuerySearchResult firstResult = queryResults.stream().findFirst().get().queryResult();
    final boolean hasSuggest = firstResult.suggest() != null;
    final boolean hasProfileResults = firstResult.hasProfileResults();
    // count the total (we use the query result provider here, since we might not get any hits (we scrolled past them))
    final Map<String, List<Suggestion>> groupedSuggestions = hasSuggest ? new HashMap<>() : Collections.emptyMap();
    final Map<String, ProfileShardResult> profileResults = hasProfileResults ? new HashMap<>(queryResults.size()) : Collections.emptyMap();
    int from = 0;
    int size = 0;
    for (SearchPhaseResult entry : queryResults) {
        QuerySearchResult result = entry.queryResult();
        from = result.from();
        // sorted queries can set the size to 0 if they have enough competitive hits.
        size = Math.max(result.size(), size);
        if (hasSuggest) {
            assert result.suggest() != null;
            for (Suggestion<? extends Suggestion.Entry<? extends Suggestion.Entry.Option>> suggestion : result.suggest()) {
                List<Suggestion> suggestionList = groupedSuggestions.computeIfAbsent(suggestion.getName(), s -> new ArrayList<>());
                suggestionList.add(suggestion);
                if (suggestion instanceof CompletionSuggestion) {
                    CompletionSuggestion completionSuggestion = (CompletionSuggestion) suggestion;
                    completionSuggestion.setShardIndex(result.getShardIndex());
                }
            }
        }
        if (bufferedTopDocs.isEmpty() == false) {
            assert result.hasConsumedTopDocs() : "firstResult has no aggs but we got non null buffered aggs?";
        }
        if (hasProfileResults) {
            String key = result.getSearchShardTarget().toString();
            profileResults.put(key, result.consumeProfileResult());
        }
    }
    final Suggest reducedSuggest;
    final List<CompletionSuggestion> reducedCompletionSuggestions;
    if (groupedSuggestions.isEmpty()) {
        reducedSuggest = null;
        reducedCompletionSuggestions = Collections.emptyList();
    } else {
        reducedSuggest = new Suggest(Suggest.reduce(groupedSuggestions));
        reducedCompletionSuggestions = reducedSuggest.filter(CompletionSuggestion.class);
    }
    final InternalAggregations aggregations = reduceAggs(aggReduceContextBuilder, performFinalReduce, bufferedAggs);
    final SearchProfileShardResults shardResults = profileResults.isEmpty() ? null : new SearchProfileShardResults(profileResults);
    final SortedTopDocs sortedTopDocs = sortDocs(isScrollRequest, bufferedTopDocs, from, size, reducedCompletionSuggestions);
    final TotalHits totalHits = topDocsStats.getTotalHits();
    return new ReducedQueryPhase(totalHits, topDocsStats.fetchHits, topDocsStats.getMaxScore(), topDocsStats.timedOut, topDocsStats.terminatedEarly, reducedSuggest, aggregations, shardResults, sortedTopDocs, firstResult.sortValueFormats(), numReducePhases, size, from, false);
}
Also used : TotalHits(org.apache.lucene.search.TotalHits) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) Suggest(org.opensearch.search.suggest.Suggest) Suggestion(org.opensearch.search.suggest.Suggest.Suggestion) CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) InternalAggregations(org.opensearch.search.aggregations.InternalAggregations) SearchProfileShardResults(org.opensearch.search.profile.SearchProfileShardResults) QuerySearchResult(org.opensearch.search.query.QuerySearchResult) SearchPhaseResult(org.opensearch.search.SearchPhaseResult) IntArrayList(com.carrotsearch.hppc.IntArrayList) List(java.util.List) ArrayList(java.util.ArrayList) ProfileShardResult(org.opensearch.search.profile.ProfileShardResult)

Example 5 with Suggestion

use of org.opensearch.search.suggest.Suggest.Suggestion in project OpenSearch by opensearch-project.

the class SuggestPhase method execute.

public void execute(SearchContext context) {
    final SuggestionSearchContext suggest = context.suggest();
    if (suggest == null) {
        return;
    }
    try {
        CharsRefBuilder spare = new CharsRefBuilder();
        final List<Suggestion<? extends Entry<? extends Option>>> suggestions = new ArrayList<>(suggest.suggestions().size());
        for (Map.Entry<String, SuggestionSearchContext.SuggestionContext> entry : suggest.suggestions().entrySet()) {
            SuggestionSearchContext.SuggestionContext suggestion = entry.getValue();
            Suggester<SuggestionContext> suggester = suggestion.getSuggester();
            Suggestion<? extends Entry<? extends Option>> result = suggester.execute(entry.getKey(), suggestion, context.searcher(), spare);
            if (result != null) {
                assert entry.getKey().equals(result.name);
                suggestions.add(result);
            }
        }
        context.queryResult().suggest(new Suggest(suggestions));
    } catch (IOException e) {
        throw new OpenSearchException("I/O exception during suggest phase", e);
    }
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) SuggestionContext(org.opensearch.search.suggest.SuggestionSearchContext.SuggestionContext) Suggestion(org.opensearch.search.suggest.Suggest.Suggestion) Entry(org.opensearch.search.suggest.Suggest.Suggestion.Entry) SuggestionContext(org.opensearch.search.suggest.SuggestionSearchContext.SuggestionContext) Option(org.opensearch.search.suggest.Suggest.Suggestion.Entry.Option) OpenSearchException(org.opensearch.OpenSearchException) CharsRefBuilder(org.apache.lucene.util.CharsRefBuilder) Map(java.util.Map)

Aggregations

Suggestion (org.opensearch.search.suggest.Suggest.Suggestion)5 CompletionSuggestion (org.opensearch.search.suggest.completion.CompletionSuggestion)4 Entry (org.opensearch.search.suggest.Suggest.Suggestion.Entry)3 PhraseSuggestion (org.opensearch.search.suggest.phrase.PhraseSuggestion)3 TermSuggestion (org.opensearch.search.suggest.term.TermSuggestion)3 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 BytesReference (org.opensearch.common.bytes.BytesReference)2 ToXContent (org.opensearch.common.xcontent.ToXContent)2 XContentParser (org.opensearch.common.xcontent.XContentParser)2 XContentType (org.opensearch.common.xcontent.XContentType)2 Option (org.opensearch.search.suggest.Suggest.Suggestion.Entry.Option)2 IntArrayList (com.carrotsearch.hppc.IntArrayList)1 Collections (java.util.Collections)1 List (java.util.List)1 Set (java.util.Set)1 Predicate (java.util.function.Predicate)1 Supplier (java.util.function.Supplier)1 TotalHits (org.apache.lucene.search.TotalHits)1