其他分享
首页 > 其他分享> > Elasticsearch Search API之(Request Body Search 查询主体

Elasticsearch Search API之(Request Body Search 查询主体

作者:互联网

preference

查询选择副本分片的倾向性(即在一个复制组中选择副本的分片值。默认情况下,es以未指定的顺序从可用的碎片副本中进行选择,副本之间的路由将在集群章节更加详细的介绍 。可以通过该字段指定分片倾向与选择哪个副本。preference可选值:

explain

是否解释各分数是如何计算的。

1GET /_search
2{
3    "explain": true,
4    "query" : {
5        "term" : { "user" : "kimchy" }
6    }
7}

version

如果设置为true,则返回每个命中文档的当前版本号。

1GET /_search
2{
3    "version": true,
4    "query" : {
5        "term" : { "user" : "kimchy" }
6    }
7}

Index Boost

当搜索多个索引时,允许为每个索引配置不同的boost级别。当来自一个索引的点击率比来自另一个索引的点击率更重要时,该属性则非常方便。
使用示例如下:

1GET /_search
2{
3    "indices_boost" : [
4        { "alias1" : 1.4 },
5        { "index*" : 1.3 }
6    ]
7}

min_score

指定返回文档的最小评分,如果文档的评分低于该值,则不返回。

1GET /_search
2{
3    "min_score": 0.5,
4    "query" : {
5        "term" : { "user" : "kimchy" }
6    }
7}

Named Queries

每个过滤器和查询都可以在其顶级定义中接受_name。搜索响应中每个匹配文档中会增加matched_queries结构体,记录该文档匹配的查询名称。查询和筛选器的标记只对bool查询有意义。
java示例如下:

 1public static void testNamesQuery() {
 2        RestHighLevelClient client = EsClient.getClient();
 3        try {
 4            SearchRequest searchRequest = new SearchRequest();
 5            searchRequest.indices("esdemo");
 6            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 7            sourceBuilder.query(
 8                    QueryBuilders.boolQuery()
 9                        .should(QueryBuilders.termQuery("context", "fox").queryName("q1"))
10                        .should(QueryBuilders.termQuery("context", "brown").queryName("q2"))
11                    );
12            searchRequest.source(sourceBuilder);
13            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
14            System.out.println(result);
15        } catch (Throwable e) {
16            e.printStackTrace();
17        } finally {
18            EsClient.close(client);
19        }
20    }

返回结果如下:

 1{
10    "hits":{
19                "_source":{
20                    "context":"My quick brown as fox eats rabbits on a regular basis.",
21                    "title":"Keeping pets healthy"
22                },
23                "matched_queries":[
24                    "q1",
25                    "q2"
26                ]
27            }
41        ]
42    }
43}

正如上面所说,每个匹配文档中都包含matched_queries,表明该文档匹配的是哪个查询条件。

Inner hits

用于定义内部嵌套层的返回规则,其inner hits支持如下选项:

field collapsing(字段折叠)

允许根据字段值折叠搜索结果。折叠是通过在每个折叠键上只选择排序最高的文档来完成的。有点类似于聚合分组,其效果类似于按字段进行分组,默认命中的文档列表第一层由该字段的第一条信息,也可以通过允许根据字段值折叠搜索结果。折叠是通过在每个折叠键上只选择排序最高的文档来完成的。例如下面的查询为每个用户检索最佳twee-t,并按喜欢的数量对它们进行排序。
下面首先通过示例进行展示field colla-psing的使用。
1)首先查询发的推特内容中包含elast-icsearch的推文:

 1GET /twitter/_search
 2{
 3    "query": {
 4        "match": {
 5            "message": "elasticsearch"
 6        }
 7    },
 8    "collapse" : {
 9        "field" : "user" 
10    },
11    "sort": ["likes"]
12}

返回结果:

 1{

13        "hits":[
14            {
15                "_index":"mapping_field_collapsing_twitter",
16                "_type":"_doc",
17                "_id":"OYnecmcB-IBeb8B-bF2X",
18                "_score":null,
19                "_source":{
20                    "message":"to be a elasticsearch",
21                    "user":"user2",
22                    "likes":3
23                },
24                "sort":[
25                    3
26                ]
27            },
84        ]
85    }
86}

首先上述会列出所有用户的推特,如果只想每个用户只显示一条推文,并且点赞率最高,或者每个用户只显示2条推文呢?这个时候,按字段折叠就闪亮登场了。java demo如下:

 1public static void search_field_collapsing() {
 2        RestHighLevelClient client = EsClient.getClient();
 3        try {
 4            SearchRequest searchRequest = new SearchRequest();
 5            searchRequest.indices("mapping_field_collapsing_twitter");
 6            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 7            sourceBuilder.query(
 8                    QueryBuilders.matchQuery("message","elasticsearch")
 9            );
10            sourceBuilder.sort("likes", SortOrder.DESC);
11            CollapseBuilder collapseBuilder = new CollapseBuilder("user");
12            sourceBuilder.collapse(collapseBuilder);
13            searchRequest.source(sourceBuilder);
14            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
15            System.out.println(result);
16        } catch (Throwable e) {
17            e.printStackTrace();
18        } finally {
19            EsClient.close(client);
20        }
21    }

其结果如下:

 1{
10    "hits":{
11  
13        "hits":[
14            {
15                "_index":"mapping_field_collapsing_twitter",
16                "_type":"_doc",
17                "_id":"OYnecmcB-IBeb8B-bF2X",
18                "_score":null,
19                "_source":{
20                    "message":"to be a elasticsearch",
21                    "user":"user2",
22                    "likes":3
23                },
24                "fields":{
25                    "user":[
26                        "user2"
27                    ]
28                },
29                "sort":[
30                    3
31                ]
32            },
33            {
34                "_index":"mapping_field_collapsing_twitter",
35                "_type":"_doc",
36                "_id":"OInecmcB-IBeb8B-bF2G",
37                "_score":null,
38                "_source":{
39                    "message":"elasticsearch is very high",
40                    "user":"user1",
41                    "likes":3
42                },
43                "fields":{
44                    "user":[
45                        "user1"
46                    ]
47                },
48                "sort":[
49                    3
50                ]
51            }
52        ]
53    }
54}

上面的示例只返回了每个用户的第一条数据,如果需要每个用户返回2条数据呢?可以通过inner_hit来设置。

 1public static void search_field_collapsing() {
 2        RestHighLevelClient client = EsClient.getClient();
 3        try {
 4            SearchRequest searchRequest = new SearchRequest();
 5            searchRequest.indices("mapping_field_collapsing_twitter");
 6            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 7            sourceBuilder.query(
 8                    QueryBuilders.matchQuery("message","elasticsearch")
 9            );
10            sourceBuilder.sort("likes", SortOrder.DESC);
11            CollapseBuilder collapseBuilder = new CollapseBuilder("user");
12
13            InnerHitBuilder collapseHitBuilder = new InnerHitBuilder("collapse_inner_hit");
14            collapseHitBuilder.setSize(2);
15            collapseBuilder.setInnerHits(collapseHitBuilder);
16            sourceBuilder.collapse(collapseBuilder);
17
18            searchRequest.source(sourceBuilder);
19            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
20            System.out.println(result);
21        } catch (Throwable e) {
22            e.printStackTrace();
23        } finally {
24            EsClient.close(client);
25        }
26    }

返回结果如下:

  1{
  2    "took":42,
  3    "timed_out":false,
  4    "_shards":{
  5        "total":5,
  6        "successful":5,
  7        "skipped":0,
  8        "failed":0
  9    },
 10    "hits":{
 11        "total":5,
 12        "max_score":null,
 13        "hits":[
 14            {
 15                "_index":"mapping_field_collapsing_twitter",
 16                "_type":"_doc",
 17                "_id":"OYnecmcB-IBeb8B-bF2X",
 18                "_score":null,
 19                "_source":{
 20                    "message":"to be a elasticsearch",
 21                    "user":"user2",
 22                    "likes":3
 23                },
 24                "fields":{
 25                    "user":[
 26                        "user2"
 27                    ]
 28                },
 29                "sort":[
 30                    3
 31                ],
 32                "inner_hits":{
 33                    "collapse_inner_hit":{
 34                        "hits":{
 35                            "total":2,
 36                            "max_score":0.19363807,
 37                            "hits":[
 38                                {
 39                                    "_index":"mapping_field_collapsing_twitter",
 40                                    "_type":"_doc",
 41                                    "_id":"OonecmcB-IBeb8B-bF2q",
 42                                    "_score":0.19363807,
 43                                    "_source":{
 44                                        "message":"to be elasticsearch",
 45                                        "user":"user2",
 46                                        "likes":3
 47                                    }
 48                                },
 49                                {
 50                                    "_index":"mapping_field_collapsing_twitter",
 51                                    "_type":"_doc",
 52                                    "_id":"OYnecmcB-IBeb8B-bF2X",
 53                                    "_score":0.17225473,
 54                                    "_source":{
 55                                        "message":"to be a elasticsearch",
 56                                        "user":"user2",
 57                                        "likes":3
 58                                    }
 59                                }
 60                            ]
 61                        }
 62                    }
 63                }
 64            },
 65            {
 66                "_index":"mapping_field_collapsing_twitter",
 67                "_type":"_doc",
 68                "_id":"OInecmcB-IBeb8B-bF2G",
 69                "_score":null,
 70                "_source":{
 71                    "message":"elasticsearch is very high",
 72                    "user":"user1",
 73                    "likes":3
 74                },
 75                "fields":{
 76                    "user":[
 77                        "user1"
 78                    ]
 79                },
 80                "sort":[
 81                    3
 82                ],
 83                "inner_hits":{
 84                    "collapse_inner_hit":{
 85                        "hits":{
 86                            "total":3,
 87                            "max_score":0.2876821,
 88                            "hits":[
 89                                {
 90                                    "_index":"mapping_field_collapsing_twitter",
 91                                    "_type":"_doc",
 92                                    "_id":"O4njcmcB-IBeb8B-Rl2H",
 93                                    "_score":0.2876821,
 94                                    "_source":{
 95                                        "message":"elasticsearch is high db",
 96                                        "user":"user1",
 97                                        "likes":1
 98                                    }
 99                                },
100                                {
101                                    "_index":"mapping_field_collapsing_twitter",
102                                    "_type":"_doc",
103                                    "_id":"N4necmcB-IBeb8B-bF0n",
104                                    "_score":0.2876821,
105                                    "_source":{
106                                        "message":"very likes elasticsearch",
107                                        "user":"user1",
108                                        "likes":1
109                                    }
110                                }
111                            ]
112                        }
113                    }
114                }
115            }
116        ]
117    }
118}

此时,返回结果是两级,第一级,还是每个用户第一条消息,然后再内部中嵌套inner_hits。

Search After

Elasticsearch支持的第三种分页获取方式,该方法不支持跳转页面。
es支持的分页方式目前已知:

  1. 通过from和size,当时当达到深度分页时,成本变的非常高昂,故es提供了索引参数:index.max_result_window来控制(from + size)的最大值,默认为10000,超过该值后将报错。
  2. 通过scroll滚动API,该方式类似于快照的工作方式,不具备实时性,并且滚动上下文的存储需要耗费一定的性能。
    本节将介绍第3种分页方式,search after,基于上一页查询的结果进行下一页数据的查询。基本思想是选择一组排序字段,能做到全局唯一。es的排序查询响应结果中会返回sort数组,包含本排序字段的最大值,下一页查询将该组字段当成查询条件,es在此数据的基础下返回下一批合适的数据。
    java示例如下:
 1public static void search_search_after() {
 2        RestHighLevelClient client = EsClient.getClient();
 3        try {
 4            SearchRequest searchRequest = new SearchRequest();
 5            searchRequest.indices("mapping_search_after");
 6            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 7            sourceBuilder.query(
 8                    QueryBuilders.termQuery("user","user2")
 9            );
10            sourceBuilder.size(1);
11            sourceBuilder.sort("id", SortOrder.ASC);
12            searchRequest.source(sourceBuilder);
13            SearchResponse result = client.search(searchRequest, RequestOptions.DEFAULT);
14            System.out.println(result);
15            if(hasHit(result)) { // 如果本次匹配到数据
16                // 省略处理数据逻辑
17                // 继续下一批查询
18                // result.getHits().
19                int length = result.getHits().getHits().length;
20                SearchHit aLastHit = result.getHits().getHits()[length - 1];
21                //开始下一轮查询
22                sourceBuilder.searchAfter(aLastHit.getSortValues());
23                result = client.search(searchRequest, RequestOptions.DEFAULT);
24                System.out.println(result);
25            }
26        } catch (Throwable e) {
27            e.printStackTrace();
28        } finally {
29            EsClient.close(client);
30        }
31    }
32    private static boolean hasHit(SearchResponse result) {
33        return !( result.getHits() == null ||
34                result.getHits().getHits() == null ||
35                result.getHits().getHits().length < 1 );
36    }

更多文章请关注微信公众号:
Elasticsearch Search API之(Request Body Search 查询主体

广告:作者新书《RocketMQ技术内幕》已上市
Elasticsearch Search API之(Request Body Search 查询主体
《RocketMQ技术内幕》已出版上市,目前可在主流购物平台(京东、天猫等)购买,本书从源码角度深度分析了RocketMQ NameServer、消息发送、消息存储、消息消费、消息过滤、主从同步HA、事务消息;在实战篇重点介绍了RocketMQ运维管理界面与当前支持的39个运维命令;并在附录部分罗列了RocketMQ几乎所有的配置参数。本书得到了RocketMQ创始人、阿里巴巴Messaging开源技术负责人、Linux OpenMessaging 主席的高度认可并作序推荐。目前是国内第一本成体系剖析RocketMQ的书籍。

标签:Body,Search,search,searchRequest,Request,sourceBuilder,field,user,result
来源: https://blog.51cto.com/15023237/2559368