Elastic Stack:es 搜索入门
一.搜索
搜索所有:
GET /index/_search
返回结果解释:
took:耗时几毫秒
time_out:是否超时,默认不超时,设置超时时间后,当搜索超时后,停止搜索,并返回已经搜索到的数据。
配置方法:search.default_search_timeout
_shards:到几个分片搜索,成功几个,跳过几个,失败几个。
hits.total:查询结果的数量
hit.max_score:对搜索的相关度的匹配分数,分数越高,就越匹配
hit.hits:包含搜索结果document的所有详细数据。
传参:
GET /book/_search?q=name:java&sort=price:desc
相当于oracle中:select * from book where name like '%java%' order by price desc
多索引搜索:一次性搜索多个index和多个type下的数据
GET /index1,index2/_search:同时搜索两个index下的数据 GET /index*/_search:按照通配符去匹配多个索引
应用场景:生产环境log索引可以按照日期分开。
log_201911
log_201912
log_202001
二.分页搜索
#从第四条数据开始搜索一页,一页两条 GET /book/_search?from=3&size=2
deep paging:根据相关度评分倒排序,所以分页过深,协调节点会将大量数据聚合分析。
deep paging性能低,应该较少使用。
三.query string基础语法
GET /book/_search?q=name:java 搜索name中包含java关键字的
GET /book/_search?q=+name:java 搜索name中包含java关键字的
GET /book/_search?q=-name:java 搜索name中不包含java关键字的
_all metadata:
GET /book/_search?q=java,直接搜索所有的field,任意一个field包含java,都可以搜索出来。
四.query DSL
DSL:domain specified language 特定领域的语言,es特有的搜索语言,可以在请求体重携带搜索条件。
查询全部:
GET /book/_search { "query": { "match_all": {} } }
排序
GET /book/_search { "query" : { "match" : { "name" : " java" } }, "sort": [ { "price": "desc" } ] }
分页:
GET /book/_search { "query": { "match_all": {} }, "from": 0, "size": 1 }
指定返回字段:
GET /book/_search { "query": { "match_all": {} }, "_source": ["name", "studymodel"] }
DSL语法:
一.
{ QUERY_NAME: { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } 二.
{ QUERY_NAME: { FIELD_NAME: { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } }
搜索需求:title必须包含elasticsearch,content可以包含elasticsearch也可以不包含,author_id必须不为111
GET /website/_doc/_search { "query": { "bool": { "must": [ { "match": { "title": "elasticsearch" } } ], "should": [ { "match": { "content": "elasticsearch" } } ], "must_not": [ { "match": { "author_id": 111 } } ] } } }
全文检索:
match_all查询全部:
GET /book/_search { "query": { "match_all": {} } }
match:全文检索
GET /book/_search { "query": { "match": { "description": "java程序员" } } }
multi_match:在多个属性中去查
GET /book/_search { "query": { "multi_match": { "query": "java程序员", "fields": ["name", "description"] } } }
range_query 范围查询
GET /book/_search { "query": { "range": { "price": { "gte": 80, "lte": 90 } } } }
term: 字段为keyword时,存储和搜索都不分词
例子:查询分词为"java程序员"
GET /book/_search { "query": { "term": { "description": "java程序员" } } }
terms:
例子:同个一个字段中,查询同时包含"search","full_text","nosql"三个分词的文档
GET /book/_search { "query": { "terms": { "tag": [ "search", "full_text", "nosql" ] }} }
exists:含有某些字段的文档
例子:查询包含price字段的文档
GET /_search { "query": { "exists": { "field": "price" } } }
fuzzy:返回包含与搜索词类似的词的文档,该词由Levenshtein编辑距离度量。
有一下几种情况:
-
-
删除字符(aple→apple)
-
插入字符(sick→sic)
-
调换两个相邻字符(ACT→CAT)
GET /book/_search { "query": { "fuzzy": { "description": { "value": "jave" } } } }
ids:根据文档id进行查询
GET /book/_search { "query": { "ids" : { "values" : ["1", "4", "100"] } } }
prefix:前缀查询
GET /book/_search { "query": { "prefix": { "description": { "value": "spring" } } } }
regexp:正则查询
GET /book/_search { "query": { "regexp": { "description": { "value": "j.*a", "flags" : "ALL", "max_determinized_states": 10000, "rewrite": "constant_score" } } } }
五.filter
需求:用户查询description中有"java程序员",并且价格大于80小于90的数据。
filter:对全文检索的结果进行过滤
GET /book/_search { "query": { "bool": { "must": [ { "match": { "description": "java程序员" } } ], "filter": { "range": { "price": { "gte": 80, "lte": 90 } } } } } }
filter与query对比:
query,会去计算每个document相对于搜索条件的相关度,并按照相关度进行排序。
query,相反,要计算相关度分数,按照分数进行排序,而且无法cache结果
当只写"filter",不写" must",就会报错,只过滤的正确写法如下,加上constant_score。
GET /book/_search { "query": { "constant_score": { "filter": { "term": { "description": "java" } } } } }
定制排序规则:
GET /book/_search { "query": { "constant_score": { "filter": { "term": { "description": "java" } } } }, "sort": [ { "price": { "order": "desc" } } ] }
方案一:通常解决方案是,将一个text field建立两次索引,一个分词,用来进行搜索;一个不分词,用来进行排序。
方案二:在创建索引的时候设置:fielddate:true
六.执行计划
一般用在那种特别复杂庞大的搜索下,比如你一下子写了上百行的搜索,这个时候可以先用validate api去验证一下,搜索是否合法。
GET /book/_validate/query?explain { "query": { "fuzzy": { "description": { "value": "jave" } } } }
七.srcoll分批查询
场景:下载某一个索引中1亿条数据,到文件或是数据库。不能一下全查出来,系统内存溢出。所以使用scoll滚动搜索技术,一批一批查询。
scoll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,是不会让用户看到的
每次发送scroll请求,我们还需要指定一个scoll参数,指定一个时间窗口,每次搜索请求只要在这个时间窗口内能完成就可以了。
第一次搜索:
GET /book/_search?scroll=1m { "query": { "match_all": {} }, "size": 3 }
返回:
{ "_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAMOkWTURBNDUtcjZTVUdKMFp5cXloVElOQQ==", "took" : 3, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ ] } }
获得的结果会有一个scoll_id,下一次再发送scoll请求的时候,必须带上这个scoll_id
GET /_search/scroll { "scroll": "1m", "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAMOkWTURBNDUtcjZTVUdKMFp5cXloVElOQQ==" }