ElasticSearch搜索API
一、search api的基础语法介绍
1、search api
GET _search
GET index1,index2/type1,type2/_search?q=value&from=0&size=10
2、GET中携带reques body http协议中,一般不允许GET请求写到request body,为了更好描述数据查询操作,还是可以使用
如果遇到不支持的场景,可以使用POST
二、Query DSL搜索语法
1、小实例
GET /_search
{
"query":{
"match_all": {}
}
}
2、Query DSL基本语法
{
query_name: {
argument: value,
argument: value,
...
}
}
{
query_name: {
field_name: {
argument: value,
argument: value,
}
}
}
示例
GET /index/type/_search
{
"query": {
"match":{
"field": "value"
}
}
}
3、组合多个搜索条件
GET /index/type/_search
{
"query": {
"bool": {
"must": {"match": {"name": "Tom"}},
"should": [
"match": {"age": 23},
{
"bool": {
"must": {"match": {"address": "beijing"}},
"must_not": {"match": {"rude": true}}
}
}
],
"minimum_should_match": 1
}
}
}
示例
# 准备3条数据
PUT /website/article/1
{
"title": "elasticsearch title",
"content": "this is a elasticsearch content",
"author": "Peng Shiyu"
}
PUT /website/article/2
{
"title": "hadoop title",
"content": "this is a hadoop content",
"author": "Peng Shiyu"
}
PUT /website/article/3
{
"title": "hbase title",
"content": "this is a hbase content",
"author": "mouday"
}
GET /website/article/_search
# 搜索条件,author包含peng,title可以包含elasticsearch
GET /website/article/_search
{
"query": {
"bool": {
"must": {
"match": {
"author": "peng"
}
},
"should": {
"match": {
"title": "elasticsearch"
}
}
}
}
}
三、filter与query深入对比解密:相关度,性能
1、filter示例
GET /website/article/_search
{
"query": {
"bool": {
"must": {
"match": {
"author": "peng"
}
},
"filter": {
"match": {
"title": "hadoop"
}
}
}
}
}
2、filter 和 query比对 filter 仅仅按照搜索条件过滤出需要的数据,不计算相关度 query 会计算每个document相对搜索条件的相关度,并按照相关度排序
3、filter和 query性能 filter 可以使用内置自动cache query 要计算相关度分数,无法使用cache
四、常用的各种query搜索语法
1、match_all
GET /index/type/_search
{
"query": {
"match_all": {}
}
}
2、match
GET /index/type/_search
{
"query": {
"match": {
"field": "value"
}
}
}
3、multi match
GET /index/type/_search
{
"query": {
"multi_match": {
"query": "text",
"fields": ["title", "content"]
}
}
}
4、range query
GET /index/type/_search
{
"query": {
"range": {
"age": {
"gte": 20,
"lt": 30
}
}
}
}
5、term query 整串查询,不分词
GET /index/type/_search
{
"query": {
"term": {
"field": "value"
}
}
}
6、terms query
GET /index/type/_search
{
"query": {
"terms": {
"field": ["value1", "value2"]
}
}
}
7、exist query 查询字段不能为空(2.x版本)
GET /index/type/_search
{
"query": {
"exists": {
"field": "value1"
}
}
}
五、多搜索条件组合查询
bool -query -should -must -must_not -filter
只过滤,不排序示例
"query": {
"constant_score": {
"filter": {
"range": {
"age": {
"gte": 30
}
}
}
}
}
组合分数计算: 先计算每个document针对他的相关度分数,然后bool综合所有分数,合并为一个分数 filter 不计算分数
六、定位不合法的搜索以及其原因
GET /index/type/_validate/query?explain
{
"query": {
"match": {
"feild": "value"
}
}
}
一般用在特别复杂的搜索语句检查,验证搜索语句是否合法
七、定制搜索结果的排序规则
定制排序规则
PUT /alibaba/taobao/1
{
"name": "dog",
"price": 20
}
PUT /alibaba/taobao/2
{
"name": "cat",
"price": 25
}
PUT /alibaba/taobao/3
{
"name": "pig",
"price": 23
}
# 按照价格大到小排序
GET /alibaba/taobao/_search
{
"sort": {
"price": {
"order": "desc"
}
}
}
八、将一个field索引两次来解决字符串排序问题
如果对一个string field进行排序,结果往往不准确, 因为分词后是多个单词,再排序就不是我们想要的结果了
通常的解决方案是: 将一个string field建立两次索引,一个分词,用于搜索;一个不分词,用来排序
PUT /website
{
"mappings": {
"article": {
"properties": {
"title": {
"type": "text",
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
},
"fielddata": true
},
"content": {
"type": "text"
},
"post_date": {
"type": "date"
},
"author_id": {
"type": "long"
}
}
}
}
}
# 查看mapping
GET /website/_mapping/article
{
"website": {
"mappings": {
"article": {
"properties": {
"author_id": {
"type": "long"
},
"content": {
"type": "text"
},
"post_date": {
"type": "date"
},
"title": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
},
"fielddata": true
}
}
}
}
}
}
填充数据
PUT /website/article/1
{
"title": "title 1",
"content": "content 1",
"post_date": "2019-04-30",
"author_id": 1001
}
PUT /website/article/2
{
"title": "title 2",
"content": "content 2",
"post_date": "2019-05-30",
"author_id": 1002
}
PUT /website/article/3
{
"title": "title 3",
"content": "content 3",
"post_date": "2019-04-28",
"author_id": 1001
}
分词后的排序结果
GET /website/article/_search
{
"sort": [
{
"title": {
"order": "desc"
}
}
]
}
{
"took": 26,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "website",
"_type": "article",
"_id": "2",
"_score": null,
"_source": {
"title": "title 2",
"content": "content 2",
"post_date": "2019-05-30",
"author_id": 1002
},
"sort": [
"title"
]
},
{
"_index": "website",
"_type": "article",
"_id": "1",
"_score": null,
"_source": {
"title": "title 1",
"content": "content 1",
"post_date": "2019-04-30",
"author_id": 1001
},
"sort": [
"title"
]
},
{
"_index": "website",
"_type": "article",
"_id": "3",
"_score": null,
"_source": {
"title": "title 3",
"content": "content 3",
"post_date": "2019-04-28",
"author_id": 1001
},
"sort": [
"title"
]
}
]
}
}
使用排序属性排序结果
GET /website/article/_search
{
"sort": [
{
"title.raw": {
"order": "desc"
}
}
]
}
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": null,
"hits": [
{
"_index": "website",
"_type": "article",
"_id": "3",
"_score": null,
"_source": {
"title": "title 3",
"content": "content 3",
"post_date": "2019-04-28",
"author_id": 1001
},
"sort": [
"title 3"
]
},
{
"_index": "website",
"_type": "article",
"_id": "2",
"_score": null,
"_source": {
"title": "title 2",
"content": "content 2",
"post_date": "2019-05-30",
"author_id": 1002
},
"sort": [
"title 2"
]
},
{
"_index": "website",
"_type": "article",
"_id": "1",
"_score": null,
"_source": {
"title": "title 1",
"content": "content 1",
"post_date": "2019-04-30",
"author_id": 1001
},
"sort": [
"title 1"
]
}
]
}
}
九、相关度评分TF&IDF算法独
1、relevance score算法 计算索引文本与搜索文本的关联匹配度
ElasticSearch使用TF/IDF算法 term frequency/ inverse document frequency算法 TF: 搜索文本中的各个词条在field文本中出现次数,出现次数越多,就越相关 IDF: 搜索文本中各个词条在整个索引的所有文档中出现的次数,出现次数越多,就越不相关 field length norm : field长度越长,相关度越弱
举例: doc1: hello, you and world is very good doc2: hello, how are you
2、score计算
GET /website/article/_search?explain
{
"query": {
"match": {
"title": "title"
}
}
}
3、分析一个document是如何被匹配上的
GET /website/article/1/_explain
{
"query": {
"match": {
"title": "title"
}
}
}
十、内核级知识点之doc value
搜索的时候,主要依靠倒排索引; 排序的时候,需要依靠正排索引,看到每个document的每个field 然后进行排序,所谓的正排索引,其实就是doc values
在建立索引的时候,一方面会建立倒排索引,以供搜索使用 一方面会建立正排索引,也就是doc values,以供排序、聚合、过滤等操作使用 doc values是被保存在磁盘上的,此时,如果内存足够,os会自动将其缓存到内存中,性能还是会很高 如果内存不足够,os会将其写入磁盘上
十一、内核解密之query phase
1、query phase (1)搜索请求发送到某一个coordinate node,构建一个priority queue,长度以paging操作from和size为准,默认为0 (2)coordinate node将请求转发到所有的shard,每个shard本地搜索,并构建一个本地的priority queue (3)各个shard将自己的priority queue(doc id)返回给coordinate node,并构建一个全局的priority queue
2、replica shard提升搜索吞吐量 一次请求要打到所有的shard的一个replica/primary上,如果每个shard都有多个replica, 那么同时并发过来的搜索请求可以同时打到其他的replica上去
十二、内核解密之fetch phase
1、工作流程 (1)coordinate node构建完priority queue之后,就发送mget请求去所有的shard上获取对应的document (2)各个shard将document返回给coordinate node (3)coodinate node将合并后的document结果返回给client客户端
2、如果不加from 和size,默认from=0 size=10, 按照socre排序
十三、搜索相关参数梳理
1、preference 决定了哪些shard会被用来执行搜索操作
_primary, _primary_first, _local,
_only_node:xyz, _prefer_node:xyz,
_shard:2,3
2、bouncing results问题 两个document 排序,field值相同,不同的shard商,可能排序不同; 每次请求轮询打到不同的shard上,每次页面上看到的搜索结果的排序都不一样 这就是bouncing result,也就是跳跃的结果
解决方案 将preference设置为一个随机的字符串,比如说user_id, 让每个user每次搜索的时候都是用同一个shard上执行,就不会看到bouncing result
timeout 将查到的数据直接返回,避免查询耗时过长 routing document文档路由,routing=user_id, 这就可以让同一个user对应的数据到一个shard上去 search_type dfs_query_then_fetch 可以提升revelance sort精准度
十四、基于scroll技术滚动搜索大量数据
使用scroll滚动搜索 先搜索一批数据,然后下次在搜索一批,以此类推,知道搜索出全部的数据来 scroll搜索会在第一次搜索的时候,保存一个当前的视图快照,之后会基于该就的视图快照提供数据搜索,如果这个期间数据变更,是不会让用户看到的 采用基于_doc 进行排序的方式,性能较高哦 每次发送scroll请求,还需要指定一个scroll参数,指定一个时间窗口,每次搜索请求只要在这个时间窗口内完成就可以
size 会发送给每个shard, 因此每次最多会返回size * primary shard条数据 scroll 看起来挺像分页的,但是其实使用场景不一样,分页主要是用来一页一页搜索,给用户的, scroll主要是用来一批一批检索数据,让系统进行处理的
# 第一次请求
GET /website/article/_search?scroll=1m
{
"query": {
"match_all": {}
},
"sort": ["_doc"],
"size": 2
}
# 第二次请求
GET /_search/scroll
{
"scroll": "1m",
"scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAADp0FkVUUFF3UUUyUmxhV1JTdWtPRkdpd2cAAAAAAAA6dRZFVFBRd1FFMlJsYVdSU3VrT0ZHaXdnAAAAAAAAOnYWRVRQUXdRRTJSbGFXUlN1a09GR2l3ZwAAAAAAADp3FkVUUFF3UUUyUmxhV1JTdWtPRkdpd2cAAAAAAAA6eBZFVFBRd1FFMlJsYVdSU3VrT0ZHaXdn"
}