ElasticSearch 常用的查询语法简记
ES 中提供了两种查询语法
- URISearch API: 通过 uri query 参数来实现快速搜索,操作简单,但是不覆盖所有的查询语法
- Request Body: ES 提供的 DSL 查询语法,覆盖所有的查询,是使用更多的一种。
一. URISearch
URISearch 通过在url 中设置 query 参数实现快速的 CRUD 搜索,常用的参数如下:
- q: query 的简称,指定查询语句
- df -> deafult field: 指定的默认查询字段,不指定的话会查询所有字段
- sort: 指定根据哪个字段排序
- size 与 from: 用来进行分页
- timeout: 超时时间
简单实例如下:
新建一条文档
PUT test_index/doc/1
{
"user": "Alfred",
"age":14
}
下面语句表示,查询 user 字段中包含 Alfred 的文档,按照 age 进行升序排列,并第 0 个开始查询 10 个,超时时间 1s。我们 from 指定为 0,所以会从查询结果的第一个进行返回是有数据的,如果将 from 指定为 4,则表示返回第 4 到 14 位置的结果,此时结果只有一条在第一的位置,因此此时不会返回数据
GET test_index/_search?q=Alfred&df=user&sort=age:asc&from=0&size=10&timeout=1s
【1】查询模式
- 泛查询: 不指明字段,在所有字段中匹配
# 查询任意字段中包含 Alfred 的所有文档
GET test_index/_search?q=Alfred
- 指定字段查询: 查询 user 为 Alfred 的文档
# 查询 user 中包含 Alfred 的所有文档
GET test_index/_search?q=user:Alfred
- term: 一个个的单词, 匹配任意即可。比如 New York,匹配到 New 或者 York 都可以查询成功
# 查询 user 中含有 New 或者 York 的所有文档
GET test_index/_search?q=user:New York
- phrase: 词语查询,要用双引号包含,“New York”, 比如精确匹配到 “New York” 才可以
# 查询 user 中含有 "New York" 的所所有文档
GET test_index/_search?q=user:"New York"
【2】布尔操作符与分组查询
URISearch 中使用括号和布尔操作符进行条件分组查询,ES 中的布尔查询操作符如下:
AND (&&), OR(||), NOT(!), +(must), -(must_not)
括号可以用来区分查询的优先级和范围。
示例如下:
# name 中可以包含 New ,必须包含 York
GET /test_index/_search?q=name:(New +York)
# name 中包含 New, 但必须不能包含 York
GET /test_index/_search?q=name:(New -York)
# name 中同时包含 New 和 York
GET /test_index/_search?q=name:(New AND York)
# 括号用于限定,表示name 中包含 New 或者 York 的字段
# 如果不加括号就成了 name 中包含 New 或者其他所有字段中包含 York 的字段的
GET /test_index/_search?q=name:(New OR York)
几点注意:
- AND OR NOT 必须大写
- 在 URI Search 中 + 会被解析为空格,需要使用 encode 后的结果: %2B
【2】范围查询
ES 提供了对数字和日志的范围区间查询,其使用规则如下
下面是两个简单示例
GET test_search_index/_search?q=username:alfred age:>26
GET test_search_index/_search?q=birth:(>1980 and < 1990)
【3】通配符与正则表达式
URISearch 中还可以通过正则表达式以及通配符进行查询,通配符的匹配规则如下:
示例
GET test_search_index/_search?q=username:alf*
GET test_search_index/_search?q=username:/[N]?e.*/
如果熟悉正则表达式的话那么将会非常方便,但是也要注意通配符匹配和正则匹配效率较低,会占用更多的内存,因此不建议使用。 并且没有特殊需求的话千万不要将 * ? 等通配符写在最前面,不然会导致查询所有的文档,极大的影响性能
【4】模糊与近似度查询
ES 中提供了根据字符差异进行搜索的模糊查询,规则如下:
简单示例
GET test_index2/_search?q=name:New ~ 1
模糊匹配指的是可以与单词为维度进行模糊查询,比如上面例子中我们查询 roam, 模糊匹配为 1,那么和 roam 差异为 1 的 foam、roams 都可以被查询出来
近似度查询则是以 词语为维度进行模糊匹配。 上面例子中和 fox quick 差异在 5 之内的词语都会被查询出来。
上面就是 URISearch 一些常用的查询方式,下面再来看 Request Body 的查询
二. RequestBody 查询
RequestBody 是 ES 提供的 DSL 查询语句。其基于 JSON 语法定义,通过 http 将 request body 发送到 ES,是最普遍使用的查询方式。其查询方式主要分为 字段查询 和 复合查询。
1. 字段类查询
字段类查询包含两类:
* 全文匹配: 对于查询语句先进行分词处理,在与倒排索引进行比较,有 match, match_phrase 等查询类型
* 单词匹配: 不对查询条件进行分词,直接与倒排索引比较,有 term, terms 与 range 等查询类型
2. match query
match 全文检索是 ES 最基本查询方式
GET test_index/_search
{
"query":{
"match":{ # 指定查询类型为 match
# 查询 name 中有 New 或者 York 的文档
"name": {
"query": "New York"
}
}
}
}
上面整个查询的基本过程如下:
- 对查询条件进行分词: New 与 York
- 得到 name 的倒排索引
- 分别拿 New 与 York 与倒排索引进行比较,计算相关性算分
- 汇总相关性算分
- 根据相关性算分进行排序,返回匹配到的文档
关于相关性算分和 ES 的查询机制后面还会继续学习,这里不作赘述。
常用的查询选项
- operator
通过查询结果我们可以知道 match 的查询匹配条件相当于 or。即任意一个单词匹配上即可,我们可以通过 operator 指明其为 and 查询,必须匹配所有的单词才可以,示例如下:
GET test_index/_search
{
"query":{
"match":{ # 指定查询类型为 match
# 查询 name 中有 New 和 York 的文档
"name": {
"query": "New York"
"operator": "and"
}
}
}
}
- minimum_should_match
控制的最小单词匹配数,使用示例如下
GET test_index/_search
{
"query": {
"match": {
"name": {
"query": "New York",
# 虽然是 or, 但是我们要求最小匹配数为 2,必须匹配到 New 和 York 才可以成功,达到了 and 的效果。
"minimum_should_match": 2
}
}
}
}
3. match_phrase query
match_phrase 是另一种全文检索模式,与 match 模式不同的是:
- match_phrase对字段作检索,有顺序要求
- 允许有差异,可以通过 slop 指定
PUT test_index/doc/1
{
"name": "New York"
}
GET test_index/_search
{
"query": {
"match_phrase": {
# match_phrase 对单词顺序有要求,下面的条件将无法查询到结果,使用 match 可以
"name": {
"query": "York New",
}
}
}
}
# 可以通过 slop 字段指明差异度,指明为2 表示可以有两处差异,下面的语句可以查询出上面创建的文档
GET test_search_index/_search
{
"query": {
"match_phrase": {
"job": {
"query": "York New",
"slop": 2
}
}
}
}
4. Query String query
- 类似于 URISearch 的 q 查询
GET test_index/_search
{
"query": {
"query_string": {
# 默认查询字段为 name
# 查询 name 中包含 alfred 和 way 的文档
"default_field": "name",
"query": "alfred AND way"
}
}
}
GET test_search_index/_search
{
"profile": true,
"query": {
"query_string": {
# 指明查询字段,查询 name 和 job 字段中含有 alfred 或者 java 和 ruby 的文档
"fields": ["name", "job"],
"query": "alfred OR (java and ruby)"
}
}
}
上面通过 fields 指明字段列表时要注意其各个字段的数据类型要保持一致,否则会报错。
5. Simple query string
类似于 query string, 但是会忽略错误的查询语法,并且只支持一部分查询语法,注意一点:
- 不能直接使用 AND、 OR、 NOT,他们会被当做字符串来处理,要用 +、 |、 - 代替。
# 必须包含 way, 可以包含 alfred
GET test_index/_search
{
"profile": true,
"query": {
"simple_query_string": {
# name 中包含 alfred 和 way 的文档
"query": "alfred +way",
"fields": ["name"]
}
}
}
三. Term Query
Term Query 将整个查询语句作为一个单词进行查询,不对查询语句做分词处理
GET test_index/_search
{
"query": {
"term": {
"name": "New York"
}
}
}
GET test_index/_search
{
"query": {
"terms": {
"name": [
# 可以分开指定
"New",
"York"
]
}
}
}
2. range query
针对数值和日期的范围查询, 操作有:
- gt 大于
- gte 大于等于
- lt 小于
- lte 小于等于
GET test_index/_search
{
"query": {
"range": {
"age": {
"gte": 10,
"lte": 20
}
}
}
}
GET test_search_index/_search
{
"query": {
"range": {
"birth": {
"gte": "1980-01-01",
"lte": "2000-01-01"
}
}
}
}
GET test_search_index/_search
{
"query": {
"range": {
"birth": {
# 灵活的日期计算方式
"gte": "now-50y"
}
}
}
}
复合查询
复合查询主要包含以下几类:
- constant_score query:
- bool: filter, must, must_not, should
- dis_max
- function_score
bool 查询
该查询有四种查询情况, 如图
GET index/doc/_search
{
"query": {
"bool": {
"filter":[{}], # 支持数组
"must":[{}],
"must_not":[{}],
"should":[{}]
}
}
}
- filter 只查询符合条件的结果,不进行相关性算分,并且会有智能缓存,因此在不需要做相关性算分的时候推荐使用 filter
GET test_search_index/_search
{
"query": {
"bool": {
"filter": {
"term":{
"name": "alfred"
}
}
}
}
}
# match contain
GET test_search_index/_search
{
"query": {
"bool": {
# must 会影响相关性算分,
"must": [
{"term": {"username": "alfred"}},
{"match":{"job": "java"}}
]
}
}
}
GET test_search_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"job": "java"
}
}
],
"must_not": [
{
"match":{
"job":"ruby"
}
}
]
}
}
}
GET test_search_index/_search
{
"query": {
"bool": {
# 只包含 should 的时候,文档必须满足至少一个条件,
# 可以通过 minimum_should_match 控制匹配的数量
"should": [
{"term": {"job": "java"}},
{"term": {"job": "ruby"}},
{"term": {"job": "specialist"}}
],
"minimum_should_match": 2
}
}
}
如果结合 must 相同,不要求必须至少满足 should 中的一个条件,但如果满足的话,查询出的结果其相关性算分会高
count API 与_source
- count 用来做计数,当只需要统计,不需要实际数据时使用,类似于 Django ORM 中的 count(),当只需要获取文档数不需要获取文档内容时使用
GET test_search_index/_count
{
"query": {
"match": {
"username": "New York"
}
}
}
- _source: 用来过滤要显示的字段,否则默认是返回所有字段的
# 指定返回字段
GET test_search_index/_search
{
"_source": ["username", "age"]
}
# 匹配过滤
GET test_search_index/_search
{
"_source": {
"excludes": "*g*",
"includes": "*er*"
}
}
以上就是 ElasticSearcb 中一些常用的查询 API 的使用,更多的内容还是需要参考官方文档: Search API 文档 与 Query DSL 文档