Search相关
- search api 概览
- uri search 详解
- term 与 phrase
- 布尔操作符
- 范围查询,支持数值和日期
- 通配符查询
- request body search
- 字段类查询
- 复合查询
- Count API
- Source Filtering
- 相关性算分
search api 概览
- search api 实现对es中存储的数据进行查询分析,endpoint为 _search,
//对所有索引查询
GET /_search
//指定单个索引查询
GET /my_index/_search
//指定索引查询,一次可查多个
GET /my_index1,my_index2/_search
GET /my_*/_search
- 查询主要有两种形式
(1)URI Search :操作简便,方便通过命令行测试;仅包含部分查询语法
GET /my_index/_search?q=user:tom
(2)Request Body Search:es 提供的完备查询语法 Query DSL(Domain Specific Language)
GET /my_index/_search
{
"query":{
"term":{
"user": "tom"
}
}
}
uri search 详解
- 通过url query 参数来实现搜索,常用参数如下:
q 制定查询的语句,语法为 Query String Synax
df q中不指定字段时,默认查询的字段,如果不指定,es 会查询所有字段
sort 排序
timeout 指定超时时间,默认不超时
from, size 用于分页
例如:查询username字段包含tom的文档,结果按照age升序排列,返回第5~14个文档,如果超过1s没有结束,则以超时结束
GET /my_index/_search?q=tom&df=username&sort=age:asc&from=4&size=10&timeout=1s
{
"profile": true //查询语句调优
}
term 与 phrase
例如:
hello word 【等效于查询 hello 或 word 两个单词】
“hello word” 【查询词语,要求先后顺序】
- 泛查询
例如:tom 【等效于在所有字段中去匹配该 term】 - 指定字段
例如:username: tom - Group 分组设定,使用括号指定匹配的规则
例如:
(quick OR brown) AND fox 【在所有字段里查询一定有fox 并且还有quick或brown 的文档】
status:(active OR pending) title:(full text search) 【查询status字段包括active或pending title字段包括full 或 text 或search】
布尔操作符
- AND(&&), OR(||), NOT(!)
例如:
name:(tom NOT lee) 【注意大写,不能小写】
name:((lee && !alfred) || (tom && lee && !alfred)) - ”+“ ” -“ 分别对应 must 和 must_not
例如:name:(tom -alfred) +lee - ”+“ 在url()中会被解析为空格,要使用encode后的结果才可以,为%2B
例如:name:(tom %2Balfred)
范围查询,支持数值和日期
- 区间写法,闭区间用 [], 开区间用 {}
例如:
age:[1 TO 10] 意为 1<=age<=10
age:[1 TO 10} 意为 1<=age<10
age:[1 TO ] 意为 age>=1
age:[* TO 10] 意为 age<=10 - 算数符号写法
例如:
age:>=1
age:(>=1&&<=10) 或者 age:(+>=1 +<=10)
通配符查询
- ?代表1个字符,* 代表0或者多个字符
例如:
name:t?m
name:tom*
name:t*m - 通配符匹配执行效率低,且占用较多内存,不建议使用;无特殊要求,不要将?/* 放在最前面
- 正则表达式 ,也不建议使用,吃内存
例如: name:/[mb]oat/ - 模糊匹配 fuzzy query
例如:name:roam~1 【匹配与roam差一个字符的词】 - 近似度查询 proximity search
例如:“fox quick”~5 【以单词为单位进行差异比较,比如”quick fox “ "quick brown fox"都会被匹配】
request body search
- request body search 将查询语句通过 http request body 发送到 es,主要包括如下参数
query 符合 Query DEL 语法的查询语句
from,size
sort 等
GET /my_index/_search
{
"query":{
"term":{"username": "tom"}
}
}
- Query DSL
基于JSON定义的查询语言,主要包括如下两种类型:
(1)字段类查询:如term,match,range等,只针对某一个字段进行查询
(2)复合查询:如bool查询等,包含一个或多个字段类查询或者复合查询语句
字段类查询
字段类查询主要包括以下两类
- 全文匹配:针对text类型的字段进行全文检索,会对查询语句先进行分词处理,如 match,match_phrase 等 query 类型
(1)Match Query 对字段做全文检索,最基础和常用的查询类型,API示例如下:
GET my_index/_search
{
"profile": true
"query":{
"match":{ //关键词
"username": "tom lee" //查询username字段有 tom或者lee的
}
}
}
match query 流程
通过operator 参数可以控制单词间的匹配关系,可选项为 or 和 and
GET my_index/_search
{
"profile": true
"query":{
"match":{ //关键词
"username": {
"query": "tom lee",
"operator": "and"
}
}
}
}
通过 minimum_should_match 参数可以控制需要匹配的单词数
GET my_index/_search
{
"profile": true
"query":{
"match":{ //关键词
"username": {
"query": "php ruby engineer",
"minimum_should_match ": "2" //上面查询语句有2个单词符合就查询出
}
}
}
}
(2)Match Phrase Query 对字段做检索,有顺序要求,API示例如下:
GET my_index/_search
{
"profile": true
"query":{
"match_phrase":{ //关键词
"job": "php engineer" //只能查到php单词在engineer之前的
}
}
}
通过 slop 参数可以控制单词间的间隔
GET my_index/_search
{
"profile": true
"query":{
"match_phrase":{ //关键词
"job": {
"query": "php engineer",
"slop ": "1" //上面查询单词间允许有1个单词的差异
}
}
}
}
(3)Query String Query 类似于URI Search 中的q参数查询 ,API示例如下:
GET my_index/_search
{
"query":{
"query_string":{ //关键词
"default_field":"job", //指明默认查询的字段名
"query": "php engineer"
}
}
}
- 单词匹配:不会对查询语句做分词处理,直接去匹配字段的倒排索引,如 term,terms,range 等 query 类型
(1)TermQuery 将查询语句作为整个单词进行查询,不会对查询语句做分词处理,API示例如下:
GET my_index/_search
{
"profile": true
"query":{
"term":{ //关键词
"username": "tom lee" //查询username字段有"tom lee"的
}
}
}
(2)TermsQuery 一次传入多个单词进行查询, API示例如下:
GET my_index/_search
{
"profile": true
"query":{
"terms":{ //关键词
"username":[ "tom", "lee"]
}
}
}
(3)RangeQuery 范围查询主要针对数值和日期类型, API示例如下:
GET my_index/_search
{
"query":{
"range":{ //关键词
"age":{
"gte": 10,
"lte": 20
}
}
}
}
RangeQuery - Date Math 针对日期提供的一种更友好的计算方式,格式如下:
now - 1d 【now: 基准日期,也可以是具体的日期,比如2020-03-04,使用具体日期的时候要用||做分隔;- 1d : 计算公式,主要有如下3种:+1h - 加一小时、-1d - 减一天、/d - 将时间舍入到天】
单位主要有如下几种: y(years)、M(months)、w(weeks)、d(days)、h(hours)、m(minutes)、s(seconds)
复合查询
复合型查询是指包含字段类查询或复合查询的类型,主要包括一下几类:
constant_score query、bool query、dis_max query、function_score query、boosting query
(1)constant_score query 该查询将其内部的查询结果文档得分都设定为1或者boost的指;多用于结合bool查询实现自定义得分
GET my_index/_search
{
"query":{
"constant_score":{ //关键词
"filter":{ //只能有一个
"match":{
"username":"alfred"
}
}
}
}
}
(2)bool query 该查询有一个或者多个布尔子句组成,主要包括如下4个:
参数 | 含义 |
filter | 只过滤符合条件的文档,不计算相关性得分 |
must | 是数组,文档必须符合must中的所有条件,会影响相关性得分 |
must_not | 文档必须不符合must_not 中的所有条件 |
should | 文档可以符合should中的所有条件,会影响相关性得分 |
API示例如下:
GET my_index/_search
{
"query":{
"bool":{ //关键词
"filter":[
{}
],
"must":[
{}
],
"must_not":[
{}
],
"should":[
{}
]
}
}
}
}
== filter:es针对filter会有智能缓存,因此其执行效率很高;做简单匹配查询且不考虑算分时,推荐使用filter代替query ==
GET my_index/_search
{
"query":{
"bool":{ //关键词
"filter":[{
"term":{
"username":"alfred"
}
}]
}
}
}
** must ** 查询username包含alfred并且job包含php关键词的文档列表
GET my_index/_search
{
"query":{
"bool":{ //关键词
"must":[ //2个match query 文档最终的得分为这两个查询的得分加和
{
"match":{
"username":"alfred"
}
},
{
"match":{
"job":"php"
}
}
]
}
}
}
** should** 使用分两种情况:
bool查询中只包含should,不包含must,文档必须满足至少一个条件
minimum_should_match 可以控制满足条件的个数或者百分比
GET my_index/_search
{
"query":{
"bool":{ //关键词
"should":[
{
"term":{
"job":"ruby"
}
},
{
"term":{
"job":"php"
}
},
{
"term":{
"job":"java"
}
}
],
"minimum_should_match":2 //以上条件至少满足2个
}
}
}
bool同时包含should和must时,文档不必满足should的条件,但是如果满足了,会增加相关性得分
GET my_index/_search
{
"query":{
"bool":{ //关键词
"should":[
{
"term":{
"job":"ruby"
}
}
],
"must":[
{
"term":{
"username":"tom"
}
}
]
}
}
}
(3)query context 与 filter context 的区别:当一个查询语句位于query或者filter 上下文时,es 执行的结果会不同,对比如下:
上下文类型 | 执行类型 | 使用方式 |
Query | 查找与查询语句最匹配的文档,对所有文档进行相关性算分并排序 | query;bool中的 must 和 should |
Filter | 查找与查询语句相匹配的文档 | bool中的 filter 和 must_not;constant_score中的filter |
GET my_index/_search
{
"query":{
"bool":{ //关键词
"must":[ //会算分查询
{
"term":{
"username":"tom"
}
}
],
"filter":[ //不算分查询
{
"range":{
"create_time":{"gte": “2020-02-01”}
}
}
]
},
}
}
Count API
获取符合条件的文档数,endpoint为 _count
Source Filtering
过滤返回结果中_source中的字段,主要有如下几种方式:
GET /test_index/_search?_source=username //url参数
GET /test_index/_search
{
"_source":false //不返回 _source
}
GET /test_index/_search
{
"_source":["username","job"] //返回 部分字段
}
GET /test_index/_search
{
"_source":{
"includes": "i*", //模糊匹配字段
"escludes": "birth"
}
}
相关性算分
- 相关性算分是指文档与查询语句间的相关度,英文为 relevance
通过倒排索引可以获取与查询语句相匹配的文档列表,本质是一个排序问题,排序的依据是相关性算分 - 相关性算分的几个重要概念如下:
(1)Term Frequency(TF)词频,即单词在该文档中出现的次数。词频越高,相关性越高
(2)Document Frequency(DF)文档频率,即单词出现的文档数
(3)Inverse Document Frequency(IDF)逆向文档频率,与文档频率相反,即单词出现越少,相关度越高
(4) Field-length Norm 文档越短,相关性越高 - ES 目前主要有两个相关性算分模型,如下:
(1)TF/IDF模型
(2)BM25 模型 5.x之后的默认模型,相比TF/IDF的一大优化是降低了tf在过大时的权重 - 可以通过explain参数来查看具体的计算方法,但要注意:
- (1)es的算分是按照shard进行的,即shard的分数计算是相互独立的,所以使用explain的时候注意分片数
- (2)可以通过设置索引的分片数为1来避免这个问题
PUT test_search_index
{
"settings": {
"index":{
"number_of_shards": "1"
}
}
}
GET /test_search_index
{
"explain": true,
"query":{
"match":{
"username":"alfred way"
}
}
}