搜索的端点地址可以是多索引多mapping type的。搜索的参数可作为URI请求参数给出,也可用 request body 给出。
GET /twitter/_search?q=user:kimchy
GET /twitter/tweet,user/_search?q=user:kimchy
GET /kimchy,elasticsearch/_search?q=tag:wow
GET /_all/_search?q=tag:wow
GET /_search?q=tag:wow
返回结果说明:
{
"took": 1, #耗时,毫秒
"timed_out": false, #是否超时
"_shards":{ #查询了多少个分片
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits":{
"total" : 1, #总命中数
"max_score": 1.3862944, #最高得分
"hits" : [ #本业结果文档数组
{
"_index" : "twitter", #索引名称
"_type" : "_doc", #mapping type
"_id" : "0", #文档ID
"_score": 1.3862944, #相关性得分
"_source" : {
"user" : "kimchy",
"message": "trying out Elasticsearch",
"date" : "2009-11-15T14:12:12",
"likes" : 0
}
}
]
}
}
URI 搜索方式通过URI参数来指定查询相关参数。让我们可以快速做一个查询。可用的参数请参考官网:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html
如果我们只想知道有多少文档匹配某个查询,可以这样用参数:
GET /bank/_search?q=city:b*&size=0
如果我们只想知道有没有文档匹配某个查询,可以这样用参数:
GET /bank/_search?q=city:b*&size=0&terminate_after=1
Request body 搜索方式以JSON格式在请求体中定义查询 query。请求方式可以是 GET 、POST ,示例:
GET /twitter/_search
{
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"_source": false,
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"_source": "obj.*",
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"_source": [ "obj1.*", "obj2.*" ],
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"_source": {
"includes": [ "obj1.*", "obj2.*" ],
"excludes": [ "*.description" ]
},
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"stored_fields" : "*",
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"stored_fields" : ["user", "postDate"],
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"query" : {
"match_all": {}
},
"docvalue_fields" : ["test1", "test2"]
}
GET /_search
{
"version": true,
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /_search
{
"explain": true,
"query" : {
"term" : { "user" : "kimchy" }
}
}
GET /bank/_search
{
"query": {
"match_all": {}
},
"script_fields": {
"test1": {
"script": {
"lang": "painless",
"source": "doc['balance'].value * 2"
}
},
"test2": {
"script": {
"lang": "painless",
"source": "doc['age'].value * params.factor",
"params": {
"factor": 2
}
}
}
}
}
min_score限制最低评分得分
GET /_search
{
"min_score": 0.5,
"query" : {
"term" : { "user" : "kimchy" }
}
}
post_filter后置过滤:在查询命中文档、完成聚合后,再对命中的文档进行过滤
如:要在一次查询中查询品牌为gucci且颜色为红色的shirts,同时还要得到gucci品牌各颜色的shirts的分面统计。
PUT /shirts
{
"mappings": {
"_doc": {
"properties": {
"brand": { "type": "keyword"},
"color": { "type": "keyword"},
"model": { "type": "keyword"}
}
}
}
}
PUT /shirts/_doc/1?refresh
{
"brand": "gucci",
"color": "red",
"model": "slim"
}
PUT /shirts/_doc/2?refresh
{
"brand": "gucci",
"color": "green",
"model": "seec"
}
GET /shirts/_search
{
"query": {
"bool": {
"filter": {
"term": { "brand": "gucci" }
}
}
},
"aggs": {
"colors": {
"terms": { "field": "color" }
}
},
"post_filter": {
"term": { "color": "red" }
}
}
可以指定按一个或多个字段排序,也可通过_score指定按评分值排序,_doc 按索引顺序排序。默认是按相关性评分从高到低排序。
GET /bank/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"age": {
"order": "desc"
} },
{
"balance": {
"order": "asc"
} },
"_score"
]
}
返回结果:
"hits": {
"total": 1000,
"max_score": null,
"hits": [
{
"_index": "bank",
"_type": "_doc",
"_id": "549",
"_score": 1,
"_source": {
"account_number": 549,
"balance": 1932, "age": 40, "state": "OR"
},
"sort": [
40,
1932,
1
]
}
}
- order值为asc、desc,默认asc
- _score默认是desc
- 结果中每个文档都会有排序字段值给出
对于值是数组或多值的字段,也可进行排序,通过mode参数指定按多值的哪种类型排序,总共有如下几种类型:
- min:最小值
- max:最大值
- sum:和
- avg:平均值
- median:中值
PUT /my_index/_doc/1?refresh
{
"product": "chocolate",
"price": [20, 4]
}
POST /_search
{
"query" : {
"term" : { "product" : "chocolate" }
},
"sort" : [
{"price" : {"order" : "asc", "mode" : "avg"}}
]
}
索引中,可能有的文档有该字段,有的文档没有该字段,那么在查询的时候可以指定若没有该字段的文档应该如何排序:
- _last:表示没有该字段的文档排在后面
- _first:表示没有该字段的文档排在前面
GET /_search
{
"sort" : [
{ "price" : {"missing" : "_last"} }
],
"query" : {
"term" : { "product" : "chocolate" }
}
}
GET /_search
{
"sort" : [
{
"_geo_distance" : { #距离排序关键字
"pin.location" : [-70, 40], #geo_point类型的字段
"order" : "asc",
"unit" : "km", #距离单位,km、m,默认m
"mode" : "min",
"distance_type" : "arc" #距离计算方式,arc球面、plan平面
}
}
],
"query" : {
"term" : { "user" : "kimchy" }
}
}
详细的参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#geo-sorting
GET /_search
{
"query" : {
"term" : { "user" : "kimchy" }
},
"sort" : {
"_script" : {
"type" : "number",
"script" : {
"lang": "painless",
"source": "doc['field_name'].value * params.factor",
"params" : {
"factor" : 1.1
}
},
"order" : "asc"
}
}
}
用collapse指定根据某个字段对命中结果进行折叠
GET /bank/_search
{
"query": {
"match_all": {}
},
"collapse" : {
"field" : "age"
},
"sort": ["balance"]
}
解释:先根据条件查询出结果,然后按照age字段分组,每个分组按照balance升序排序,接着从每个分组中取出第一条数据
仅仅从上述语句,我们很难判断查询结果正确与否,因此es还提供了inner_hits方式,可以在调试的时候解释折叠的结果,使用方式如下:
GET /bank/_search
{
"query": {
"match_all": {}
},
"collapse" : {
"field" : "age" ,
"inner_hits": { #指定inner_hits来解释折叠
"name": "details", #自定义命名
"size": 5, #指定每组取几个文档
"sort": [{ "balance": "asc" }] #组内排序
},
"max_concurrent_group_searches": 4 #指定组查询的并发数
},
"sort": ["balance"]
}
除此之外,inner_hits还可以返回多个角度的组内topN
GET /twitter/_search
{
"query": {
"match": {
"message": "elasticsearch"
}
},
"collapse" : {
"field" : "user",
"inner_hits": [
{
"name": "most_liked",
"size": 3,
"sort": ["likes"]
},
{
"name": "most_recent",
"size": 3,
"sort": [{ "date": "asc" }]
}
]
},
"sort": ["likes"]
}
普通分页:
GET /_search
{
"from" : 0, "size" : 10,
"query" : {
"term" : { "user" : "kimchy" }
}
}
注意:搜索请求耗用的堆内存和时间与 from + size 大小成正比。分页越深耗用越大,为了不因分页导致OOM或严重影响性能,ES中规定from + size 不能大于索引setting参数 index.max_result_window 的值,默认值为 10000。
search_after在指定文档后面取文档,可用于深度分页,即在获取下一页的时候需要传入上次获取的最后一个文档。注意:使用search_after,要求查询必须指定排序,并且这个排序组合值在每个文档唯一(最好排序中包含_id字段,这样可以保证唯一)。 search_after的值用的就是这个排序值。用search_after时 from 只能为0、-1。
首次查询第一页:
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
后续的查询:
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"search_after": [1463538857, "654323"], #传入上次最后一个文档排序的内容
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
GET twitter/_search
{
"size": 10,
"query": {
"match" : {
"title" : "elasticsearch"
}
},
"search_after": [1463538857, "654323"],
"sort": [
{"date": "asc"},
{"_id": "desc"}
]
}
#这种写法只会高亮第一个字段title
GET /hl_test/_search
{
"query": {
"match": {
"title": "lucene"
}
},
"highlight": {
"fields": {
"title": {},
"content": {}
}
}
}
#require_field_match多字段高亮
GET /hl_test/_search
{
"query": {
"match": {
"title": "lucene"
}
},
"highlight": {
"require_field_match": false,
"fields": {
"title": {},
"content": {}
}
}
}
高亮结果在返回的每个文档中以hightlight节点给出:
"highlight": {
"title": [
"lucene solr and elaticsearch"
]}
如果高亮标签不想使用默认的em,可以自定义高亮标签:
GET /hl_test/_search
{
"query": {
"match": {
"title": "lucene"
}
},
"highlight": {
"require_field_match": false,
"fields": {
"title": {
"pre_tags":[""],
"post_tags": [""]
},
"content": {}
}
}
}
高亮的详细设置请参考官网:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html
对于执行缓慢的查询,我们很想知道它为什么慢,时间都耗在哪了,可以在查询上加入上 profile 来获得详细的执行步骤、耗时信息。
GET /twitter/_search
{
"profile": true,
"query" : {
"match" : { "message" : "some number" }
}
}
信息参考官网:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-profile.html
count查询:
PUT /twitter/_doc/1?refresh
{
"user": "kimchy"
}
GET /twitter/_doc/_count?q=user:kimchy
GET /twitter/_doc/_count
{
"query" : {
"term" : { "user" : "kimchy" }
}
}
返回结果:
{
"count" : 1,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
}
}
用来检查我们的查询是否正确,以及查看底层生成查询是怎样的,比较常用的一个API
官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-validate.html
校验查询:
GET twitter/_doc/_validate/query
{
"query": {
"query_string": {
"query": "post_date:foo",
"lenient": false
}
}
}
获得查询解释:
GET twitter/_doc/_validate/query?explain=true
{
"query": {
"query_string": {
"query": "post_date:foo",
"lenient": false
}
}
}
用rewrite获得比explain更详细的解释:
GET twitter/_doc/_validate/query?rewrite=true
{
"query": {
"more_like_this": {
"like": {
"_id": "2"
},
"boost_terms": 1
}
}
}
获得所有分片上的解释:
GET twitter/_doc/_validate/query?rewrite=true&all_shards=true
{
"query": {
"match": {
"user": {
"query": "kimchy",
"fuzziness": "auto"
}
}
}
}
获得某个查询的评分解释,及某个文档是否被这个查询命中
官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-explain.html
GET /twitter/_doc/0/_explain
{
"query" : {
"match" : { "message" : "elasticsearch" }
}
}
让我们可以了解可执行查询的索引分片节点情况:
GET /twitter/_search_shards
想知道指定routing值的查询将在哪些分片节点上执行:
GET /twitter/_search_shards?routing=foo,baz
很多时候,我们可能会碰到相同的查询情况,这时候就可以定义一个查询模板,然后使用模板进行查询。
注册一个模板:
POST _scripts/<templatename>
{
"script": {
"lang": "mustache",
"source": {
"query": {
"match": {
"title": "{{query_string}}"
}
}
}
}
}
使用模板查询:
GET _search/template
{
"id": "" , #指定之前注册的模板名称
"params": {
"query_string": "search for these words" #传入查询字符串
}
}
详细请参考官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html