概要

本篇介绍Query DSL的语法案例,查询语句的调试,以及排序的相关内容。

基本语法

空查询

最简单的搜索命令,不指定索引和类型的空搜索,它将返回集群下所有索引的所有文档(默认显示10条):

GET /_search
{}
搜索多个索引
GET /index1,index2/_doc/_search
{}
指定分页搜索
GET /_search
{
"from": 0,
"size": 10
}
get带request body

HTTP协议,GET请求带body是不规范的做法,但由于ES搜索的复杂性,加上HTTP协议GET/POST方法表述的语义,GET更适合用来表述查询的动作,虽然不规范,但还是这么用了。现在大多数浏览器也支持GET+request body,如果遇到不支持的,换成POST即可。了解一下就行,不用太慌张。

查询表达式Query DSL

Query DSL是一种非常灵活、可读性高的查询语言,body为JSON格式,绝大部分功能都可以用它来展现,并且这种查询语句更纯粹,让学习者更专注于本身的功能,避免Client API的干扰。

上一节的空查询,等价于这个:

GET /_search
{
"query": {
"match_all": {}
}
}
基本语法
# 查询语句结构
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
} # 针对某个字段的查询
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}
合并查询语句

再复杂的查询语句,也是由一个一个的查询条件叠加而成的,查询语句有两种形式:

  • 叶子语句:单个条件组成的语句,如match语句,类似mysql的"id = 1"这种。
  • 复合语句:有多个条件,需要合并在一起才能组成一个完整的语句,需要使用bool进行组合,里面的条件可以用must必须匹配、must not必须不匹配、should可以匹配修饰,也可以包含过滤器filter。类似mysql的"(status = 1 && language != 'french' && (author = 'John' || author = 'Tom'))"这种。

举个例子:

{
"bool": {
"must": { "match": { "status": 1 }},
"must_not": { "match": { "language": "french" }},
"should": { "match": { "author": "John Tom" }},
"filter": { "range": { "length" : { "gt" : 30 }} }
}
}

复合语句可以嵌套,来实现更复杂的查询需求,在上面的例子上简单延伸一下:

"bool": {
"must": { "match": { "status": 1 }},
"must_not": { "match": { "language": "french" }},
"should": [
{"match": { "author": "John Tom" }},
{"bool": {
"must": { "match": { "name": "friend" }},
"must_not": { "match": { "content": "star" }}
}}
],
"filter": { "range": { "length" : { "gt" : 30 }} }
}
复合语句相关性分数计算

每一个子查询都独自地计算文档的相关性得分。一旦他们的得分被计算出来,bool 查询就将这些得分进行合并并且返回一个代表整个布尔操作的得分,得分高的显示在前面,filter内的条件不参与分数计算。

过滤器filter

我们还是以英文儿歌的索引为案例,看一个搜索需求:歌词内容包含friend,同时歌长大于30秒的记录

GET /music/children/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"content": "friend"
}
}
],
"filter": {
"range": {
"length": {
"gte": 30
}
}
}
}
}
}

filter与query

  • 过滤情况filtering context

仅按照搜索条件把需要的数据筛选出来,不计算相关度分数。

  • 查询情况query context

匹配条件的数据,会根据搜索条件的相关度,计算每个document的分数,然后按照分数进行排序,这个才是全文搜索的情况。

性能差异

filter只做过滤,不作排序,并且会缓存结果到内存中,性能非常高。

query匹配条件,要做评分,没有缓存,性能要低一些。

应用场景

filter一个非常重要的作用就是减少不相关数据对query的影响,提升query的性能,二者常常搭配在一起使用。

组合使用的时候,把期望符合条件的document的搜索条件放在query里,把要滤掉的条件放在filter里。

constant_score查询

如果一个查询只有filter过滤条件,可以用constant_score来替代bool查询,这样的查询语句更简洁、更清晰,只是没有评分,示例如下:

GET /music/children/_search
{
"query": {
"constant_score": {
"filter": {
"term": { "content": "gymbo"}
}
}
}
}

filter内不支持terms语法,注意一下。

最常用的查询

再复杂的查询语句,也是由最基础的查询变化而来的,而最常用的查询其实也就那么几个。

  1. match_all查询

查询简单的匹配所有文档

GET /_search
{
"query": {
"match_all": {}
}
}
  1. match查询

无论是全文搜索还是精确查询,match查询是最基本的标准

# 全文搜索例子
{ "match": { "content": "loves smile" }} # 精确搜索
{ "match": { "likes": 15 }}
{ "match": { "date": "2019-12-05" }}
{ "match": { "isOwner": true }}
{ "match": { "keyword": "love you" }}

对于精确值的查询,我们可以使用filter来替代,filter有缓存的效果。

  1. multi_match查询

可以在多个字段上执行相同的match查询

{
"multi_match": {
"query": "my sunshine",
"fields": [ "name", "content" ]
}
}
  1. range查询

查询指定区间内的数字或时间,query和filter都支持,一般是filter用得多,允许的操作符如下:

  • gt 大于
  • gte 大于或等于
  • lt 小于
  • lte 小于或等于
{
"range": {
"length": {
"gte": 45,
"lt": 60
}
}
}
  1. term查询

用于精确值匹配,精确值可以是数字,日期,boolean或keyword类型的字符串

{ "term": { "likes":    15           }}
{ "term": { "date": "2019-12-05" }}
{ "term": { "isOwner": true }}
{ "term": { "keyword": "love you" }}

建立索引时mapping设置为not_analyzed时,match等同于term,用得多的是match和range。

  1. terms查询

跟term类似,只是允许一次指定多个值进行匹配,只要有任何一个匹配上,都满足条件

{ "terms": { "content": [ "love", "gymbo", "sunshine" ] }}

查询语句调试

复杂的查询语句,可能会有几百行,可以先使用调试工具检测一下查询语句,定位不合法的搜索及原因,完整语法如下:

GET /index/type/_validate/query?explain
{
"query": {
...
}
}

explain参数可以提供更详细的查询不合法的信息,便于问题定位。写一个错误的例子,比如使用中文标点符号:

GET /music/children/_validate/query?explain
{
"query": {
"terms": { "content“: [ "love", "gymbo", "sunshine" ] }
}
}

错误提示如下:

{
"valid": false,
"error": """
ParsingException[Failed to parse]; nested: JsonParseException[Unexpected character ('l' (code 108)): was expecting a colon to separate field name and value
at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput@5e57280e; line: 3, column: 33]];; com.fasterxml.jackson.core.JsonParseException: Unexpected character ('l' (code 108)): was expecting a colon to separate field name and value
at [Source: org.elasticsearch.transport.netty4.ByteBufStreamInput@5e57280e; line: 3, column: 33]
"""
}

valid关键字,true为验证通过,false为不通过,如上提示信息,会指明3行33列错误,原因是使用了中文的引号。将语法修正后,得到的正确响应如下:

{
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"valid": true,
"explanations": [
{
"index": "music",
"valid": true,
"explanation": "+content:(gymbo love sunshine) #*:*"
}
]
}

排序

查询请求得到的结果,默认排序是相关性得分降序。如果我们只使用filter过滤,符合filter条件的文档,评分都是一样的(bool的filter得分是null,constant_score得分是1),结果文档还是随机返回,显然这样的排序不符合我们的预期。

sort排序规则

为此,我们可以使用sort属性,对文档进行排序,sort的用法与mysql如出一辙,示例如下:

GET /music/children/_search
{
"query": {
"bool": {
"filter": { "range": { "length" : { "gt" : 30 }} }
}
},
"sort": [
{
"length": {
"order": "desc"
}
}
]
}

sort内可以同时指定多个排序字段,一旦使用sort排序后,_score得分将变成null,因为我们指定了排序规则,_score没有实际意义了,就不用耗费精力再去计算它。

字符串排序问题

我们知道text类型的字段,会有关键词分词处理,对这样的字段进行排序,结果往往都不准确,6.x版本以后的text类型,会再自动建立一个keyword类型的字段,这个字段是不分词的,所以这样就有了分工,text类型的负责搜索,keyword类型则负责排序。

我们回顾一下music索引的mapping信息(节选):

{
"music": {
"mappings": {
"children": {
"properties": {
"content": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}

例如name字段,有一个text类型的,里面fields还有一个类型为keyword,名称也为keyword的字段,所以在排序的场景中,我们应该使用name.keyword,示例如下:

GET /music/children/_search
{
"sort": [
{
"name.keyword": {
"order": "asc"
}
}
]
}

小结

本篇介绍Query DSL的语法及基础实战内容,顺带点了一下filter与query的区别,面对复杂查询语句时,建议先用验证工具进行排查,最后介绍了一下排序方面的知识,基础语法、上机案例多实践即可。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区

Elasticsearch系列---实战搜索语法的更多相关文章

  1. Elasticsearch系列---常见搜索方式与聚合分析

    概要 本篇主要介绍常见的6种搜索方式.聚合分析语法,基本是上机实战,可以和关系型数据库作对比,如果之前了解关系型数据库,那本篇只需要了解搜索和聚合的语法规则就可以了. 搜索响应报文 以上篇建立的mus ...

  2. Elasticsearch系列---初识搜索

    概要 本篇主要介绍搜索的报文结构含义.搜索超时时间的处理过程,提及了一下多索引搜索和轻量搜索,最后将精确搜索与全文搜索做了简单的对比. 空搜索 搜索API最简单的形式是不指定索引和类型的空搜索,它将返 ...

  3. Elasticsearch系列---实战零停机重建索引

    前言 我们使用Elasticsearch索引文档时,最理想的情况是文档JSON结构是确定的,数据源源不断地灌进来即可,但实际情况中,没人能够阻拦需求的变更,在项目的某个版本,可能会对原有的文档结构造成 ...

  4. Elasticsearch URI search 查询语法整理

    Elasticsearch URI search 一.请求体查询与空查询 1. 请求体查询(request body search) 简单查询语句(lite)是一种有效的命令行adhoc查询.但是,如 ...

  5. 干货 |《从Lucene到Elasticsearch全文检索实战》拆解实践

    1.题记 2018年3月初,萌生了一个想法:对Elasticsearch相关的技术书籍做拆解阅读,该想法源自非计算机领域红火已久的[樊登读书会].得到的每天听本书.XX拆书帮等. 目前市面上Elast ...

  6. Google高级搜索语法

    Google高级搜索语法   Google搜索果真是一个强悍的不得了的搜索引擎,今天转了一些 google的高级搜索语法 希望能帮助到大家. 一.allinanchor: anchor是一处说明性的文 ...

  7. elasticsearch的rest搜索--- 查询

    目录: 一.针对这次装B 的解释 二.下载,安装插件elasticsearch-1.7.0   三.索引的mapping 四. 查询 五.对于相关度的大牛的文档 四. 查询 1. 查询的官网的文档   ...

  8. webpack 多页应用架构系列实战

    阅读目录 1.webpack配置了解 2.webpack CommonsChunkPlugin公共代码剥离 3.了解ProvidePlugin的用途 回到顶部 1.webpack配置了解 webpac ...

  9. Kibana 搜索语法

    Kibana 搜索语法 Kibana 支持三种搜索语法, 分别是 Lucene query 语法, 基于 json 的 ES query语法, 以及 Kuery 语法. 前两种语法可以直接使用, Ku ...

随机推荐

  1. 【错误收集】JDK的安装 2016-02-03 14:35 725人阅读 评论(23) 收藏

    自己的jdk是根据视频的指示来安装的,首先打开网址www.java.sun.com,然后找到java se的下载,根据自己的机器系统来下载安装包,如下图: 将安装包下载好之后,双击进行安装,根据提示进 ...

  2. HDU-1260_Tickets

    Tickets Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Problem Des ...

  3. Flask学习之七 单元测试

    英文博客地址:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-vii-unit-testing 中文翻译地址:http ...

  4. Linxu 用户和用户组管理1

    Linux 系统是一个多用户任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后 以这个账号的身份进入系统. 用户的账号一方面可以帮助系统管理员对使用系统的用户进 ...

  5. 1x1卷积

    你可能会想为什么有人会用1x1卷积,因为它关注的不是一块像素,而是一个像素,图1 图1 我们看看传统的卷积,它基本上是运行在一个小块图像上的小分类器,但仅仅是个线性分类器.图2 图2 如果你在中间加一 ...

  6. Facebook F8|闲鱼高级技术专家参会分享

    笔者代表闲鱼参加了Facebook在4月30日举行的为期二天的F8大会,地点加州.将会议概括和一些收获分享给大家.对国内开发者而言,Facebook的产品设计.社区.VR/AR等有一些借鉴意义:对海外 ...

  7. iptables SNAT与伪装

    Source NAT(SNAT)的主要應用,是让同一內部網路上的多部主机,可共用同一条Internet实体连線.直接与Internet相连的闸道器,可使用SNAT(搭配连線追蹤)来来改写內部网络与In ...

  8. hdu 5734 Acperience(2016多校第二场)

    Acperience Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  9. 关于心跳ajax请求pending状态(被挂起),stalled时间过长的问题。涉及tcp连接异常。

    环境:景安快云服务器(听说很垃圾,但是公司买的,我也刚来),CentOS-6.8-x86_64,Apache,MySQL5.1,PHP5.3. 问题:现公司有一个php系统,需要重复向后台发送ajax ...

  10. EF CodeFirst 实例Demo

    一直想搞一个EFCodeFirst的Demo,让自己通过实例真正了解CodeFirst,方便以后有需求的时候可以有思路.网上查了很多资料,发现很多博主的文章大量重复,根据推荐步骤走并不一定能够成功,而 ...