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