Elasticsearch搜索引擎第九篇-搜索API

搜索API端点地址

搜索的端点地址可以是多索引多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 搜索

Request body 搜索方式以JSON格式在请求体中定义查询 query。请求方式可以是 GET 、POST ,示例:

GET /twitter/_search
{
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

指定返回字段

  • _source字段过滤源文档中包含哪些字段哪些内容
    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" }
        }
    }
    
  • stored_fields指定返回哪些stored的字段
    GET /_search
    {
        "stored_fields" : "*",
        "query" : {
            "term" : { "user" : "kimchy" }
        }
    }
    
    GET /_search
    {
        "stored_fields" : ["user", "postDate"],
        "query" : {
            "term" : { "user" : "kimchy" }
        }
    }
    
  • docvalue_fields指定返回存储了docValue的字段
    GET /_search
    {
        "query" : {
            "match_all": {}
        },
        "docvalue_fields" : ["test1", "test2"]
    }
    
  • version指定返回文档的版本字段
    GET /_search
    {
        "version": true,
        "query" : {
            "term" : { "user" : "kimchy" }
        }
    }
    
  • explain指定返回文档的评分解释(调试比较有用)
GET /_search
{
    "explain": true,
    "query" : {
        "term" : { "user" : "kimchy" }
    }
}

script_fields脚本对字段进行运算

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" }
      }
    }
    

sort排序

可以指定按一个或多个字段排序,也可通过_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": [
	"<em>lucene</em> solr and elaticsearch"
  ]}

如果高亮标签不想使用默认的em,可以自定义高亮标签:

GET /hl_test/_search
{
  "query": {
    "match": {
      "title": "lucene"
    }
  },
  "highlight": {
    "require_field_match": false,
    "fields": {
      "title": {
        "pre_tags":["<strong>"],
        "post_tags": ["</strong>"]
      },
      "content": {}
    }
  }
}

高亮的详细设置请参考官网:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html

profile调试、优化

对于执行缓慢的查询,我们很想知道它为什么慢,时间都耗在哪了,可以在查询上加入上 profile 来获得详细的执行步骤、耗时信息。

GET /twitter/_search
{
  "profile": true,
  "query" : {
    "match" : { "message" : "some number" }
  }
}

信息参考官网:
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-profile.html

count API

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
    }
}

validate API

用来检查我们的查询是否正确,以及查看底层生成查询是怎样的,比较常用的一个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"
      }
    }
  }
}

explain API

获得某个查询的评分解释,及某个文档是否被这个查询命中
官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-explain.html

GET /twitter/_doc/0/_explain
{
      "query" : {
        "match" : { "message" : "elasticsearch" }
      }
}

分片查询API

让我们可以了解可执行查询的索引分片节点情况:

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": "<templateName>",   #指定之前注册的模板名称
    "params": {
        "query_string": "search for these words"  #传入查询字符串
    }
}

详细请参考官网:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-template.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值