Elastic Stack:es 搜索入门
一.搜索
搜索所有:
1 | GET /index/_search |
返回结果解释:
took:耗时几毫秒
time_out:是否超时,默认不超时,设置超时时间后,当搜索超时后,停止搜索,并返回已经搜索到的数据。
配置方法:search.default_search_timeout
_shards:到几个分片搜索,成功几个,跳过几个,失败几个。
hits.total:查询结果的数量
hit.max_score:对搜索的相关度的匹配分数,分数越高,就越匹配
hit.hits:包含搜索结果document的所有详细数据。
传参:
1 | GET /book/_search?q=name:java&sort=price:desc |
相当于oracle中:select * from book where name like '%java%' order by price desc
多索引搜索:一次性搜索多个index和多个type下的数据
1 2 | GET /index1,index2/_search:同时搜索两个index下的数据 GET /index*/_search:按照通配符去匹配多个索引 |
应用场景:生产环境log索引可以按照日期分开。
log_201911
log_201912
log_202001
二.分页搜索
1 2 | #从第四条数据开始搜索一页,一页两条 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特有的搜索语言,可以在请求体重携带搜索条件。
查询全部:
1 2 3 4 | GET /book/_search { "query" : { "match_all" : {} } } |
排序
1 2 3 4 5 6 7 8 9 10 11 | GET /book/_search { "query" : { "match" : { "name" : " java" } }, "sort" : [ { "price" : "desc" } ] } |
分页:
1 2 3 4 5 6 | GET /book/_search { "query" : { "match_all" : {} }, "from" : 0 , "size" : 1 } |
指定返回字段:
1 2 3 4 5 | GET /book/_search { "query" : { "match_all" : {} }, "_source" : [ "name" , "studymodel" ] } |
DSL语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 一.<br>{ QUERY_NAME: { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } 二.<br>{ QUERY_NAME: { FIELD_NAME: { ARGUMENT: VALUE, ARGUMENT: VALUE,... } } } |
搜索需求:title必须包含elasticsearch,content可以包含elasticsearch也可以不包含,author_id必须不为111
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | GET /website/_doc/_search { "query" : { "bool" : { "must" : [ { "match" : { "title" : "elasticsearch" } } ], "should" : [ { "match" : { "content" : "elasticsearch" } } ], "must_not" : [ { "match" : { "author_id" : 111 } } ] } } } |
全文检索:
match_all查询全部:
1 2 3 4 5 6 | GET /book/_search { "query" : { "match_all" : {} } } |
match:全文检索
1 2 3 4 5 6 7 8 | GET /book/_search { "query" : { "match" : { "description" : "java程序员" } } } |
multi_match:在多个属性中去查
1 2 3 4 5 6 7 8 9 | GET /book/_search { "query" : { "multi_match" : { "query" : "java程序员" , "fields" : [ "name" , "description" ] } } } |
range_query 范围查询
1 2 3 4 5 6 7 8 9 10 11 | GET /book/_search { "query" : { "range" : { "price" : { "gte" : 80 , "lte" : 90 } } } } |
term: 字段为keyword时,存储和搜索都不分词
例子:查询分词为"java程序员"
1 2 3 4 5 6 7 8 | GET /book/_search { "query" : { "term" : { "description" : "java程序员" } } } |
terms:
例子:同个一个字段中,查询同时包含"search","full_text","nosql"三个分词的文档
1 2 3 4 | GET /book/_search { "query" : { "terms" : { "tag" : [ "search" , "full_text" , "nosql" ] }} } |
exists:含有某些字段的文档
例子:查询包含price字段的文档
1 2 3 4 5 6 7 8 | GET /_search { "query" : { "exists" : { "field" : "price" } } } |
fuzzy:返回包含与搜索词类似的词的文档,该词由Levenshtein编辑距离度量。
有一下几种情况:
-
-
删除字符(aple→apple)
-
插入字符(sick→sic)
-
调换两个相邻字符(ACT→CAT)
1 2 3 4 5 6 7 8 9 10 | GET /book/_search { "query" : { "fuzzy" : { "description" : { "value" : "jave" } } } } |
ids:根据文档id进行查询
1 2 3 4 5 6 7 8 | GET /book/_search { "query" : { "ids" : { "values" : [ "1" , "4" , "100" ] } } } |
prefix:前缀查询
1 2 3 4 5 6 7 8 9 10 | GET /book/_search { "query" : { "prefix" : { "description" : { "value" : "spring" } } } } |
regexp:正则查询
1 2 3 4 5 6 7 8 9 10 11 12 13 | GET /book/_search { "query" : { "regexp" : { "description" : { "value" : "j.*a" , "flags" : "ALL" , "max_determinized_states" : 10000 , "rewrite" : "constant_score" } } } } |
五.filter
需求:用户查询description中有"java程序员",并且价格大于80小于90的数据。
filter:对全文检索的结果进行过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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。
1 2 3 4 5 6 7 8 9 10 11 12 | GET /book/_search { "query" : { "constant_score" : { "filter" : { "term" : { "description" : "java" } } } } } |
1 | 定制排序规则: |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | GET /book/_search { "query" : { "constant_score" : { "filter" : { "term" : { "description" : "java" } } } }, "sort" : [ { "price" : { "order" : "desc" } } ] } |
方案一:通常解决方案是,将一个text field建立两次索引,一个分词,用来进行搜索;一个不分词,用来进行排序。
方案二:在创建索引的时候设置:fielddate:true
六.执行计划
一般用在那种特别复杂庞大的搜索下,比如你一下子写了上百行的搜索,这个时候可以先用validate api去验证一下,搜索是否合法。
1 2 3 4 5 6 7 8 9 10 | GET /book/_validate/query?explain { "query" : { "fuzzy" : { "description" : { "value" : "jave" } } } } |
七.srcoll分批查询
场景:下载某一个索引中1亿条数据,到文件或是数据库。不能一下全查出来,系统内存溢出。所以使用scoll滚动搜索技术,一批一批查询。
scoll搜索会在第一次搜索的时候,保存一个当时的视图快照,之后只会基于该旧的视图快照提供数据搜索,如果这个期间数据变更,是不会让用户看到的
每次发送scroll请求,我们还需要指定一个scoll参数,指定一个时间窗口,每次搜索请求只要在这个时间窗口内能完成就可以了。
第一次搜索:
1 2 3 4 5 6 7 | GET /book/_search?scroll=1m { "query" : { "match_all" : {} }, "size" : 3 } |
返回:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | { "_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
1 2 3 4 5 | GET /_search/scroll { "scroll" : "1m" , "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAMOkWTURBNDUtcjZTVUdKMFp5cXloVElOQQ==" } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步