在 elasticSearch 中,共有两种查询:1. url 搜索 2. DSL查询语言
-
url 搜索
顾名思义, url搜索的参数都通过url来传递,方便来进行一般的数据查看,大概如下面这种形式的
GET twitter/_search?q=user:kimchy
-
Request Body 搜索
通过的 DSL(Domain Specific Language) 来定义查询语言, 像下面这个
GET /_search { "query": { "bool": { "must": [ { "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ], "filter": [ { "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ] } } }
这篇文章主要来说明 DSL 查询的原理和语法。
DSL 搜索查询
Elasticsearch提供了基于JSON的完整查询DSL(Domain Specific Language[特定于域的语言])来定义查询。将查询DSL视为查询的AST(Abstract Syntax Tree[抽象语法树]。
它由两种子句组成:
-
子句查询条件
子句查询在特定字段中查找特定值,例如match,term或range查询。这些查询可以单独使用。
-
复合查询条件
复合查询是把 子句查询和 其他复合查询组合起来,实现复杂逻辑的查询。例如bool和 dis_max 查询
相同的查询条件的结果依赖于他们的上下文环境,elasticSearch 的DSL 主要提供两种上下文环境 : query[查询上下文] 和 filter[过滤器上下文]。
filter 和 query 上下文
注意了, DLS关键是要搞清楚 filter 和 query 的差别
- 相关性得分 [relevance score]
默认情况下, ElaticSearch通过相关性得分(查询和文档的匹配程度)来对结果排序。
相关性得分是一个正浮点数,在_search API 中以 _score 字段返回。_score 值越大,相关性越高。
每种字段以不同的方式计算_score, _score的计算也根据查询条件运行于 filter 或者 query 而不同。
- 结构化查询
在 query 上下文中, 一个查询条件主要解决的问题是: 条件和文档的匹配程度有多高。除了解决匹配度的问题, 还会计算一个相关性程度,作为元数据 _score 返回。
- 结构化过滤
在 filter 上下文中, 一个查询条件主要解决的问题是: 条件和文档是否匹配。通常结果是匹配和不匹配,这主要用于过滤结构化数据。
一条过滤语句会询问每个文档的字段值是否包含着特定值:
- status 字段中是为 "published" ?
- created 的日期范围是否在 2013 到 2014 ?
不论是把查询条件传递给 bool下的 filter 或者 must 参数等, 还是在 聚合中的filter, filter都会起作用
- 性能差异
使用过滤语句得到的结果集 -- 一个简单的文档列表,快速匹配运算并存入内存是十分方便的, 每个文档仅需要1个字节。这些缓存的过滤结果集与后续请求的结合使用是非常高效的。
查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比 过滤语句更耗时,并且查询结果也不可缓存。
幸亏有了倒排索引,一个只匹配少量文档的简单查询语句在百万级文档中的查询效率会与一条经过缓存 的过滤语句旗鼓相当,甚至略占上风。 但是一般情况下,一条经过缓存的过滤查询要远胜一条查询语句的执行效率。
过滤语句的目的就是缩小匹配的文档结果集,所以需要仔细检查过滤条件。
- 什么情况下使用
原则上来说,使用查询语句做全文本搜索或其他需要进行相关性评分的时候,剩下的全部用过滤语句
Use query clauses in query context for conditions which should affect the score of matching documents (i.e. how well does the document match), and use all other query clauses in filter context.
复合查询
-
bool
组合其他查询的默认查询: 如must, should, must_not, or filter
must 和 should 会把score 合并起来, 越匹配越好
must_not 和 filter 则在filter 条件中执行
-
booting query
增加正匹配查询的匹配分数, 减少负匹配的查询分数。
-
constant_score query
包含另一个查询的查询, 但是所有文档使用同一score, 在过滤器上下文执行
全文搜索查询
-
common terms query
大概可以理解为优先级查询, 比如 not happy, 会优先查询含有 happy的文档
忽略或者从结构中去过滤一些高频率词的查询匹配,通常如 the, a, not 等副词,来提高搜索效率 ,这些词通常单独没有意义,组合起来又不可缺少, 例如 happy 和 not happy, common 首先搜索happy,得到的结果中过滤 在对not happy 计算_score.
-
intervals query
intervals query 允许用户精确控制查询词在文档中出现的先后关系,实现了对terms顺序、terms之间的距离以及它们之间的包含关系的灵活控制
这个查询匹配 my_text 中" my favorite food is cold porridge.", 但是不会匹配 "it's cold my favorite food is porridge."
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "my favorite food",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "hot water" } },
{ "match" : { "query" : "cold porridge" } }
]
}
}
]
}
}
}
}
}
-
match
匹配文本,数字,日期或布尔值等文档,在执行文本匹配之前,首先会 分析查询词汇。
match是full-text搜索的默认查询,包含模糊查询。match 的语法结构:
{
"query":{
"match": {
<field_name>: { // field_name 是match 的 top-level 参数
"query" : "" // 查询内容
"analyzer": "" // 分词器
"operator" "OR[默认], AND" //用于解释 query中的bool逻辑
.....
}
}
}
}
-
match phrase query
短语查询, 查询条件按照一个词来处理
例如: "He is" 只能查询到"He is a student", 而不能查询到 "He said that is a monstor."
-match phrase prefix query
短语前缀查询, 查询文本的最后一项是单词的前缀
```
GET /_search
{
"query": {
"match_phrase_prefix" : {
"message" : {
"query" : "quick brown f"
}
}
}
}
```
-
multi match query
match 的扩展, 可以规定多个字符串匹配.
语法结构和 match 稍有不同
GET /_search
{
"query": {
"multi_match" : {
"query": "Will Smith",
"type": "best_fields",
"fields": [ "first_name", "last_name" ], // field 可以是很多个
"operator": "and"
}
}
}
term-level 查询
查询结构化数据中的精确值, term-level 不对搜索文本进行分析, 它匹配精确的值。
exists
-
fuzzy
自动模糊查询
ids
GET /_search
{
"query": {
"ids" : {
"values" : ["1", "4", "100"]
}
}
}
- preix
GET /_search
{
"query": {
"prefix": {
"user": {
"value": "ki"
}
}
}
}
- range
GET _search
{
"query": {
"range" : {
"age" : {
"gte" : 10,
"lte" : 20,
"boost" : 2.0
}
}
}
}
regexp
-
term
返回在特定字段中内容完全相同的文档。
可以term去找一个有精确值字段【价格,productID或用户名】的文档。
避免在类型为text字段上使用term, 要使用请使用 match。 elasticSearch 会对text字段使用analysis, 这会导致term 搜索边的困难
GET /_search { "query": { "term": { "user": { "value": "Kimchy", "boost": 1.0 } } } }
-
terms
terms的多字段形式
term_set
- wildcard