Elasticsearch源码分析十四--搜索类型

来源:互联网 发布:网络摄像头密码 编辑:程序博客网 时间:2024/06/15 00:48
  • 简介
  • query_then_fetch
  • query_and_fetch
  • dfs_query_and_fetch
  • dfs_query_then_fetch
  • count
  • scan

简介

Elasticsearch允许通过指定搜索类型来选择查询在内部如何处理。不同的搜索类型适合不同的情况;
可以只在乎性能,但有时查询的关联性可能是最重要的因素。使用search_type请求参数指定搜索类型,
其各种取值介绍参考下文,其中size参数指定一次查询中返回的最大文档数。默认值为0。在Elasticsearch代码中,会将上述几种搜索类型分隔成几个阶段phrases顺序执行,
前提是可以分成两个阶段。比如query_and_fetch不能分解成两个阶段,只需一步就能完成查询。
而dfs_query_then_fetch需要三个阶段。这几种搜索类型最终会调用具体的搜索类SearchService,
该类的介绍参考另一篇文章。

query_then_fetch

此搜索类型分两步,第一步:执行查询得到对文档进行排序和分级所需信息。这一步在所有的分片上执行。然后,只在相关分片上
查询文档的实际内容。不同于query_and_fetch,此查询类型返回结果的最大数量等于size参数的值。默认使用这个类型。
public class TransportSearchQueryThenFetchAction extends TransportSearchTypeAction {        '''执行请求'''        @Override    protected void doExecute(SearchRequest searchRequest, ActionListener<SearchResponse> listener) {        new AsyncAction(searchRequest, listener).start();    }    private class AsyncAction extends BaseAsyncAction<QuerySearchResult> {                '''第一阶段是queryphrase'''        @Override        protected String firstPhaseName() {            return "query";        }        @Override        protected void sendExecuteFirstPhase(DiscoveryNode node, ShardSearchRequest request, SearchServiceListener<QuerySearchResult> listener) {            '''调用SearchServiceTransportAction发送query请求'''            searchService.sendExecuteQuery(node, request, listener);        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段'''        @Override        protected void moveToSecondPhase()         { ... }    }}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

query_and_fetch

这通常是最快也最简单的搜索类型实现。查询在所有分片上并行执行(当然,任意一个主分片,只查询一个副本),所有分片
返回等于size值的结果数。返回文档的最大数量等于size的值乘以分片的数量。
public class TransportSearchQueryAndFetchAction extends TransportSearchTypeAction {        '''执行请求'''        @Override    protected void doExecute(SearchRequest searchRequest, ActionListener<SearchResponse> listener) {        new AsyncAction(searchRequest, listener).start();    }    private class AsyncAction extends BaseAsyncAction<QuerySearchResult> {                '''只有query_fetch'''        @Override        protected String firstPhaseName() {            return "query_fetch";        }        @Override        protected void sendExecuteFirstPhase(DiscoveryNode node, ShardSearchRequest request, SearchServiceListener<QueryFetchSearchResult> listener) {            '''调用SearchServiceTransportAction发送fetch请求'''            searchService.sendExecuteFetch(node, request, listener);        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段,对于该搜索类型,                     第二阶段无须再查询'''        @Override        protected void moveToSecondPhase() throws Exception {            try {                innerFinishHim();            } catch (Throwable e) {                ReduceSearchPhaseException failure = new ReduceSearchPhaseException("merge", "", e, buildShardFailures());                if (logger.isDebugEnabled()) {                    logger.debug("failed to reduce search", failure);                }                listener.onFailure(failure);            }        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段'''        @Override        protected void moveToSecondPhase()         { ... }    }}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

dfs_query_and_fetch

跟query_and_fetch类似,但相比query_and_fetch,它包含一个额外阶段,在初始查询中执行分布式词频的计算,
以得到返回文件的更精确的得分,从而让查询结果更相关。
public class TransportSearchDfsQueryAndFetchAction extends TransportSearchTypeAction {        '''执行请求'''        @Override    protected void doExecute(SearchRequest searchRequest, ActionListener<SearchResponse> listener) {        new AsyncAction(searchRequest, listener).start();    }    private class AsyncAction extends BaseAsyncAction<QuerySearchResult> {                '''第一阶段是dfs'''        @Override        protected String firstPhaseName() {            return "dfs";        }        @Override        protected void sendExecuteFirstPhase(DiscoveryNode node, ShardSearchRequest request, SearchServiceListener<DfsSearchResult> listener) {            '''调用SearchServiceTransportAction发送dfs请求'''            searchService.sendExecuteDfs(node, request, listener);        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段'''        protected void moveToSecondPhase() {            for (final AtomicArray.Entry<DfsSearchResult> entry : firstResults.asList()) {                DfsSearchResult dfsResult = entry.value;                DiscoveryNode node = nodes.get(dfsResult.shardTarget().nodeId());                if (node.id().equals(nodes.localNodeId())) {                    localOperations++;                } else {                    QuerySearchRequest querySearchRequest = new QuerySearchRequest(request, dfsResult.id(), dfs);                    '''执行第二阶段fetch'''                    executeSecondPhase(entry.index, dfsResult, counter, node, querySearchRequest);                }            }            ...        }    }}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

dfs_query_then_fetch

与前一个dfs_query_and_ fetch一样,dfs_query_then_fetch类似于相应的query_then_fetch,但比query_ then_fetch多了一个额外的阶段,就像dfs_query_and_fetch一样。
public class TransportSearchDfsQueryThenFetchAction extends TransportSearchTypeAction {        '''执行请求'''        @Override    protected void doExecute(SearchRequest searchRequest, ActionListener<SearchResponse> listener) {        new AsyncAction(searchRequest, listener).start();    }    private class AsyncAction extends BaseAsyncAction<QuerySearchResult> {                '''第一阶段是dfs'''        @Override        protected String firstPhaseName() {            return "dfs";        }        @Override        protected void sendExecuteFirstPhase(DiscoveryNode node, ShardSearchRequest request, SearchServiceListener<DfsSearchResult> listener) {            '''调用SearchServiceTransportAction发送dfs请求'''            searchService.sendExecuteDfs(node, request, listener);        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段'''                protected void moveToSecondPhase() {            final AggregatedDfs dfs = searchPhaseController.aggregateDfs(firstResults);            final AtomicInteger counter = new AtomicInteger(firstResults.asList().size());            int localOperations = 0;            for (final AtomicArray.Entry<DfsSearchResult> entry : firstResults.asList()) {                DfsSearchResult dfsResult = entry.value;                DiscoveryNode node = nodes.get(dfsResult.shardTarget().nodeId());                if (node.id().equals(nodes.localNodeId())) {                    localOperations++;                } else {                    QuerySearchRequest querySearchRequest = new QuerySearchRequest(request, dfsResult.id(), dfs);                    '''执行第二阶段query'''                    executeQuery(entry.index, dfsResult, counter, querySearchRequest, node);                }            }           ...        }        void executeQuery(final int shardIndex, final DfsSearchResult dfsResult, final AtomicInteger counter, final QuerySearchRequest querySearchRequest, DiscoveryNode node) {            searchService.sendExecuteQuery(node, querySearchRequest, new SearchServiceListener<QuerySearchResult>() {                @Override                public void onResult(QuerySearchResult result) {                    result.shardTarget(dfsResult.shardTarget());                    queryResults.set(shardIndex, result);                    if (counter.decrementAndGet() == 0) {                            '''执行第三个阶段fetch'''                        executeFetchPhase();                    }                }                 }          }}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

count

一个特殊的搜索,只返回匹配查询的文档数。如果你只需要结果数量,而不关心文档,
应该使用这个搜索类型。
public class TransportSearchCountAction extends TransportSearchTypeAction {        '''执行请求'''        @Override    protected void doExecute(SearchRequest searchRequest, ActionListener<SearchResponse> listener) {        new AsyncAction(searchRequest, listener).start();    }    private class AsyncAction extends BaseAsyncAction<QuerySearchResult> {                '''第一阶段是query'''        @Override        protected String firstPhaseName() {            return "query";        }        @Override        protected void sendExecuteFirstPhase(DiscoveryNode node, ShardSearchRequest request, SearchServiceListener<QuerySearchResult> listener) {            '''调用SearchServiceTransportAction发送query请求'''            searchService.sendExecuteQuery(node, request, listener);        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段,此搜索类型第二个阶段无需查询'''        protected void moveToSecondPhase() {                        protected void moveToSecondPhase() throws Exception {            // no need to sort, since we know we have no hits back            final InternalSearchResponse internalResponse = searchPhaseController.merge(SearchPhaseController.EMPTY_DOCS, firstResults, (AtomicArray<? extends FetchSearchResultProvider>) AtomicArray.empty());            String scrollId = null;            if (request.scroll() != null) {                scrollId = buildScrollId(request.searchType(), firstResults, null);            }            listener.onResponse(new SearchResponse(internalResponse, scrollId, expectedSuccessfulOps, successulOps.get(), buildTookInMillis(), buildShardFailures()));        }    }}  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

scan

另一个特殊的搜索类型,只有在要让查询返回大量结果时才用。它跟一般的查询有点不同,因为在发送第一个请
求之后, Elasticsearch响应一个滚动标识符,类似于关系型数据库中的游标。
所有查询需要在_search/scroll REST端点运行,并需要在请求主体中发送返回的滚动标识符。
public class TransportSearchScanAction extends TransportSearchTypeAction {        '''执行请求'''        @Override    protected void doExecute(SearchRequest searchRequest, ActionListener<SearchResponse> listener) {        new AsyncAction(searchRequest, listener).start();    }    private class AsyncAction extends BaseAsyncAction<QuerySearchResult> {                '''第一阶段是init_scan'''        @Override        protected String firstPhaseName() {            return "init_scan";        }        @Override        protected void sendExecuteFirstPhase(DiscoveryNode node, ShardSearchRequest request, SearchServiceListener<QuerySearchResult> listener) {            '''调用SearchServiceTransportAction发送scan请求'''            searchService.sendExecuteScan(node, request, listener);        }                '''在其父类TransportSearchTypeAction的onFirstPhaseResult函数中调用                     在收到第一阶段的处理结果后转移到第二阶段,此搜索类型第二个阶段无需查询'''        @Override        protected void moveToSecondPhase() throws Exception {            final InternalSearchResponse internalResponse = searchPhaseController.merge(SearchPhaseController.EMPTY_DOCS, firstResults, (AtomicArray<? extends FetchSearchResultProvider>) AtomicArray.empty());            String scrollId = null;            if (request.scroll() != null) {                scrollId = buildScrollId(request.searchType(), firstResults, ImmutableMap.of("total_hits", Long.toString(internalResponse.hits().totalHits())));            }            listener.onResponse(new SearchResponse(internalResponse, scrollId, expectedSuccessfulOps, successulOps.get(), buildTookInMillis(), buildShardFailures()));        }    }}
原创粉丝点击