Search in sources :

Example 31 with SearchPhaseResult

use of org.opensearch.search.SearchPhaseResult in project OpenSearch by opensearch-project.

the class SearchPhaseController method validateMergeSortValueFormats.

/**
 * Checks that query results from all shards have consistent unsigned_long format.
 * Sort queries on a field that has long type in one index, and unsigned_long in another index
 * don't work correctly. Throw an error if this kind of sorting is detected.
 * //TODO: instead of throwing error, find a way to sort long and unsigned_long together
 */
private static void validateMergeSortValueFormats(Collection<? extends SearchPhaseResult> queryResults) {
    boolean[] ulFormats = null;
    boolean firstResult = true;
    for (SearchPhaseResult entry : queryResults) {
        DocValueFormat[] formats = entry.queryResult().sortValueFormats();
        if (formats == null)
            return;
        if (firstResult) {
            firstResult = false;
            ulFormats = new boolean[formats.length];
            for (int i = 0; i < formats.length; i++) {
                ulFormats[i] = formats[i] == DocValueFormat.UNSIGNED_LONG_SHIFTED ? true : false;
            }
        } else {
            for (int i = 0; i < formats.length; i++) {
                // if the format is unsigned_long in one shard, and something different in another shard
                if (ulFormats[i] ^ (formats[i] == DocValueFormat.UNSIGNED_LONG_SHIFTED)) {
                    throw new IllegalArgumentException("Can't do sort across indices, as a field has [unsigned_long] type " + "in one index, and different type in another index!");
                }
            }
        }
    }
}
Also used : DocValueFormat(org.opensearch.search.DocValueFormat) SearchPhaseResult(org.opensearch.search.SearchPhaseResult)

Example 32 with SearchPhaseResult

use of org.opensearch.search.SearchPhaseResult in project OpenSearch by opensearch-project.

the class SearchPhaseController method merge.

/**
 * Enriches search hits and completion suggestion hits from <code>sortedDocs</code> using <code>fetchResultsArr</code>,
 * merges suggestions, aggregations and profile results
 *
 * Expects sortedDocs to have top search docs across all shards, optionally followed by top suggest docs for each named
 * completion suggestion ordered by suggestion name
 */
public InternalSearchResponse merge(boolean ignoreFrom, ReducedQueryPhase reducedQueryPhase, Collection<? extends SearchPhaseResult> fetchResults, IntFunction<SearchPhaseResult> resultsLookup) {
    if (reducedQueryPhase.isEmptyResult) {
        return InternalSearchResponse.empty();
    }
    ScoreDoc[] sortedDocs = reducedQueryPhase.sortedTopDocs.scoreDocs;
    SearchHits hits = getHits(reducedQueryPhase, ignoreFrom, fetchResults, resultsLookup);
    if (reducedQueryPhase.suggest != null) {
        if (!fetchResults.isEmpty()) {
            int currentOffset = hits.getHits().length;
            for (CompletionSuggestion suggestion : reducedQueryPhase.suggest.filter(CompletionSuggestion.class)) {
                final List<CompletionSuggestion.Entry.Option> suggestionOptions = suggestion.getOptions();
                for (int scoreDocIndex = currentOffset; scoreDocIndex < currentOffset + suggestionOptions.size(); scoreDocIndex++) {
                    ScoreDoc shardDoc = sortedDocs[scoreDocIndex];
                    SearchPhaseResult searchResultProvider = resultsLookup.apply(shardDoc.shardIndex);
                    if (searchResultProvider == null) {
                        // TODO it would be nice to assert this in the future
                        continue;
                    }
                    FetchSearchResult fetchResult = searchResultProvider.fetchResult();
                    final int index = fetchResult.counterGetAndIncrement();
                    assert index < fetchResult.hits().getHits().length : "not enough hits fetched. index [" + index + "] length: " + fetchResult.hits().getHits().length;
                    SearchHit hit = fetchResult.hits().getHits()[index];
                    CompletionSuggestion.Entry.Option suggestOption = suggestionOptions.get(scoreDocIndex - currentOffset);
                    hit.score(shardDoc.score);
                    hit.shard(fetchResult.getSearchShardTarget());
                    suggestOption.setHit(hit);
                }
                currentOffset += suggestionOptions.size();
            }
            assert currentOffset == sortedDocs.length : "expected no more score doc slices";
        }
    }
    return reducedQueryPhase.buildResponse(hits);
}
Also used : CompletionSuggestion(org.opensearch.search.suggest.completion.CompletionSuggestion) SearchHit(org.opensearch.search.SearchHit) FetchSearchResult(org.opensearch.search.fetch.FetchSearchResult) SearchPhaseResult(org.opensearch.search.SearchPhaseResult) SearchHits(org.opensearch.search.SearchHits) ScoreDoc(org.apache.lucene.search.ScoreDoc)

Example 33 with SearchPhaseResult

use of org.opensearch.search.SearchPhaseResult in project OpenSearch by opensearch-project.

the class SearchTransportService method sendExecuteQuery.

public void sendExecuteQuery(Transport.Connection connection, final ShardSearchRequest request, SearchTask task, final SearchActionListener<SearchPhaseResult> listener) {
    // we optimize this and expect a QueryFetchSearchResult if we only have a single shard in the search request
    // this used to be the QUERY_AND_FETCH which doesn't exist anymore.
    final boolean fetchDocuments = request.numberOfShards() == 1;
    Writeable.Reader<SearchPhaseResult> reader = fetchDocuments ? QueryFetchSearchResult::new : QuerySearchResult::new;
    final ActionListener handler = responseWrapper.apply(connection, listener);
    transportService.sendChildRequest(connection, QUERY_ACTION_NAME, request, task, new ConnectionCountingHandler<>(handler, reader, clientConnections, connection.getNode().getId()));
}
Also used : ActionListener(org.opensearch.action.ActionListener) ChannelActionListener(org.opensearch.action.support.ChannelActionListener) QuerySearchResult(org.opensearch.search.query.QuerySearchResult) ScrollQuerySearchResult(org.opensearch.search.query.ScrollQuerySearchResult) SearchPhaseResult(org.opensearch.search.SearchPhaseResult) ScrollQueryFetchSearchResult(org.opensearch.search.fetch.ScrollQueryFetchSearchResult) QueryFetchSearchResult(org.opensearch.search.fetch.QueryFetchSearchResult) Writeable(org.opensearch.common.io.stream.Writeable)

Example 34 with SearchPhaseResult

use of org.opensearch.search.SearchPhaseResult in project OpenSearch by opensearch-project.

the class FetchSearchPhase method innerRun.

private void innerRun() throws Exception {
    final int numShards = context.getNumShards();
    final boolean isScrollSearch = context.getRequest().scroll() != null;
    final List<SearchPhaseResult> phaseResults = queryResults.asList();
    final SearchPhaseController.ReducedQueryPhase reducedQueryPhase = resultConsumer.reduce();
    final boolean queryAndFetchOptimization = queryResults.length() == 1;
    final Runnable finishPhase = () -> moveToNextPhase(searchPhaseController, queryResults, reducedQueryPhase, queryAndFetchOptimization ? queryResults : fetchResults.getAtomicArray());
    if (queryAndFetchOptimization) {
        assert phaseResults.isEmpty() || phaseResults.get(0).fetchResult() != null : "phaseResults empty [" + phaseResults.isEmpty() + "], single result: " + phaseResults.get(0).fetchResult();
        // query AND fetch optimization
        finishPhase.run();
    } else {
        ScoreDoc[] scoreDocs = reducedQueryPhase.sortedTopDocs.scoreDocs;
        final IntArrayList[] docIdsToLoad = searchPhaseController.fillDocIdsToLoad(numShards, scoreDocs);
        // no docs to fetch -- sidestep everything and return
        if (scoreDocs.length == 0) {
            // we have to release contexts here to free up resources
            phaseResults.stream().map(SearchPhaseResult::queryResult).forEach(this::releaseIrrelevantSearchContext);
            finishPhase.run();
        } else {
            final ScoreDoc[] lastEmittedDocPerShard = isScrollSearch ? searchPhaseController.getLastEmittedDocPerShard(reducedQueryPhase, numShards) : null;
            final CountedCollector<FetchSearchResult> counter = new CountedCollector<>(fetchResults, // we count down every shard in the result no matter if we got any results or not
            docIdsToLoad.length, finishPhase, context);
            for (int i = 0; i < docIdsToLoad.length; i++) {
                IntArrayList entry = docIdsToLoad[i];
                SearchPhaseResult queryResult = queryResults.get(i);
                if (entry == null) {
                    // no results for this shard ID
                    if (queryResult != null) {
                        // if we got some hits from this shard we have to release the context there
                        // we do this as we go since it will free up resources and passing on the request on the
                        // transport layer is cheap.
                        releaseIrrelevantSearchContext(queryResult.queryResult());
                        progressListener.notifyFetchResult(i);
                    }
                    // in any case we count down this result since we don't talk to this shard anymore
                    counter.countDown();
                } else {
                    SearchShardTarget searchShardTarget = queryResult.getSearchShardTarget();
                    Transport.Connection connection = context.getConnection(searchShardTarget.getClusterAlias(), searchShardTarget.getNodeId());
                    ShardFetchSearchRequest fetchSearchRequest = createFetchRequest(queryResult.queryResult().getContextId(), i, entry, lastEmittedDocPerShard, searchShardTarget.getOriginalIndices(), queryResult.getShardSearchRequest(), queryResult.getRescoreDocIds());
                    executeFetch(i, searchShardTarget, counter, fetchSearchRequest, queryResult.queryResult(), connection);
                }
            }
        }
    }
}
Also used : FetchSearchResult(org.opensearch.search.fetch.FetchSearchResult) ScoreDoc(org.apache.lucene.search.ScoreDoc) ShardFetchSearchRequest(org.opensearch.search.fetch.ShardFetchSearchRequest) AbstractRunnable(org.opensearch.common.util.concurrent.AbstractRunnable) SearchPhaseResult(org.opensearch.search.SearchPhaseResult) SearchShardTarget(org.opensearch.search.SearchShardTarget) IntArrayList(com.carrotsearch.hppc.IntArrayList) Transport(org.opensearch.transport.Transport)

Example 35 with SearchPhaseResult

use of org.opensearch.search.SearchPhaseResult in project OpenSearch by opensearch-project.

the class TransportSearchHelper method buildScrollId.

static String buildScrollId(AtomicArray<? extends SearchPhaseResult> searchPhaseResults, Version version) {
    boolean includeContextUUID = version.onOrAfter(LegacyESVersion.V_7_7_0);
    try {
        BytesStreamOutput out = new BytesStreamOutput();
        if (includeContextUUID) {
            out.writeString(INCLUDE_CONTEXT_UUID);
        }
        out.writeString(searchPhaseResults.length() == 1 ? ParsedScrollId.QUERY_AND_FETCH_TYPE : ParsedScrollId.QUERY_THEN_FETCH_TYPE);
        out.writeVInt(searchPhaseResults.asList().size());
        for (SearchPhaseResult searchPhaseResult : searchPhaseResults.asList()) {
            if (includeContextUUID) {
                out.writeString(searchPhaseResult.getContextId().getSessionId());
            }
            out.writeLong(searchPhaseResult.getContextId().getId());
            SearchShardTarget searchShardTarget = searchPhaseResult.getSearchShardTarget();
            if (searchShardTarget.getClusterAlias() != null) {
                out.writeString(RemoteClusterAware.buildRemoteIndexName(searchShardTarget.getClusterAlias(), searchShardTarget.getNodeId()));
            } else {
                out.writeString(searchShardTarget.getNodeId());
            }
        }
        byte[] bytes = BytesReference.toBytes(out.bytes());
        return Base64.getUrlEncoder().encodeToString(bytes);
    } catch (IOException e) {
        throw new UncheckedIOException(e);
    }
}
Also used : SearchPhaseResult(org.opensearch.search.SearchPhaseResult) SearchShardTarget(org.opensearch.search.SearchShardTarget) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) BytesStreamOutput(org.opensearch.common.io.stream.BytesStreamOutput)

Aggregations

SearchPhaseResult (org.opensearch.search.SearchPhaseResult)35 SearchShardTarget (org.opensearch.search.SearchShardTarget)17 ShardId (org.opensearch.index.shard.ShardId)16 ArrayList (java.util.ArrayList)15 ShardSearchContextId (org.opensearch.search.internal.ShardSearchContextId)12 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)9 ShardSearchRequest (org.opensearch.search.internal.ShardSearchRequest)9 QuerySearchResult (org.opensearch.search.query.QuerySearchResult)9 AtomicLong (java.util.concurrent.atomic.AtomicLong)8 ScoreDoc (org.apache.lucene.search.ScoreDoc)8 InternalSearchResponse (org.opensearch.search.internal.InternalSearchResponse)8 TopDocs (org.apache.lucene.search.TopDocs)7 AtomicArray (org.opensearch.common.util.concurrent.AtomicArray)7 IOException (java.io.IOException)6 List (java.util.List)6 CountDownLatch (java.util.concurrent.CountDownLatch)6 AtomicReference (java.util.concurrent.atomic.AtomicReference)6 CompletionSuggestion (org.opensearch.search.suggest.completion.CompletionSuggestion)6 TotalHits (org.apache.lucene.search.TotalHits)5 ActionListener (org.opensearch.action.ActionListener)5