当前位置: 首页 > 工具软件 > namesearch > 使用案例 >

Elasticsearch DSL 查询语句

史英睿
2023-12-01

简介

在 ES 中,提供了十分丰富的 DSL 查询

DSL 查询使用 JSON 格式的请求体与 ES 交互,可以实现各种各样的查询需求。

常见的查询有:

  • 查询所有:查询出所有文档,测试时才会用。如 match_all。
  • 全文检索查询:利用分词器对输入的内容分词,然后去匹配倒排索引。如 match、multi_match。
  • 精确查询:根据精确词条查询 keyword、数值、日期等。如 term、range、terms。
  • 地理信息查询:根据经纬度 geo 查询。
  • 复合查询:将上述简单查询组合起来查询。如 bool、function_score。

基本语法

使用 DSL 查询,需用到 query 参数。

基本的语法格式:

GET /索引库/_search
{
    "query": {
        "查询类型": {
            "查询条件": "值"
        }
    }
}

空查询

没有查询条件的查询,就是空查询。它会匹配所有的文档。

GET /user/_search

全文检索查询

全文查询语句用于全文本字段 text 的分词查询。

match

示例:查询 full_name 字段中包含 John 或 Smith 的文档。

GET /user/_search
{
    "query" : {
        "match" : {
            "full_name" : "John Smith"
        }
    }
}

说明: ES 会先使用分词器拆分 "John Smith" 为两个独立的词条 "John" 和 "Smith",然后再去匹配倒排索引。

这里的 full_name 字段可以替换为任何你想查询的字段甚至是 all 字段。

match 属于 boolean 的类型,也就是说,分析器会对提供的查询文本进行分析并构建 boolean 查询语句。

由 match 构建的 boolean 查询语句默认是逻辑或(or),当然,我们可以通过 operator 参数来改变这个默认行为。

示例:查询 full_name 字段中包含 John 和 Smith 的文档。

GET /user/_search
{
    "query": {
        "match" : {
            "full_name" : {
                "query" : "John Smith",
                "operator" : "and"
            }
        }
    }
}

说明: full_name 是字段名称,query 参数的值是要查询的文本,operator 参数用于设置 match 的逻辑(or 还是 and)。

match_phrase

match_phrase,即短语(词组)匹配,它会分析提供的查询文本并构建一个 phrase 查询。

match_phrase 用于精确的 phase 匹配。

示例:查询 full_name 字段中包含 "John Smith" 短语的文档。

GET /_search
{
    "query" : {
        "match_phrase" : {
            "full_name" : "John Smith"
        }
    }
}

可以给提供的查询文本指定 analyzer(分词器),如果没有指定,默认使用字段的显式 mapping 中的定义,或者默认的 search analyzer。

GET /user/_search
{
    "query": {
        "match_phrase" : {
            "full_name" : {
                "query" : "John Smith",
                "analyzer" : "standard"
            }
        }
    }
}

match_phrase_prefix

match_phrase_prefix 和 match_phrase 类似,但 match_phrase_prefix 不是精准匹配,而是前缀匹配。

示例:查询 full_name 字段中以 "John Smi" 短语开头的文档。

GET /user/_search
{
    "query" : {
        "match_phrase_prefix" : {
            "full_name" : "John Smi"
        }
    }
}

multi_match

multi_match 用于多字段匹配查询。

性能较低,建议使用 copyto 合并到 all 字段,然后使用 match。

GET /user/_search
{
    "query" : {
        "multi_match": {
          "query": "John Smith",
          "fields": ["first_name", "full_name"]
        }
    }
}

Term-level 查询

Term-level 查询是直接查询倒排索引中的精确的值。

Term-level 查询用于精确类型的用户输入查询,如数值、日期、枚举值或关键字,而不是文本(text)。

不会对用户的输入分词

term

term 用于查询指定字段的倒排索引包含某个确切值的记录。

POST /user/_search
{
    "query": {
        "term" : { 
            "first_name" : "john" 
        } 
    }
}

terms

terms 和 term 类似,只不过提供的确切的值是数组。类似于 MySQL 的 in 条件。

POST /user/_search
{
  "query": {
    "terms" : { "city" : ["bj", "sz"] } 
  }
}

range

range 用于范围查询。

GET /user/_search
{
    "query": {
        "range" : {
            "age" : {
                "gte" : 28,
                "lt" : 60
            }
        }
    }
}

prefix

prefix 返回字段的 term 以确切的前缀(前缀不会被分词)开头的记录。

GET /user/_search
{
    "query": {
        "prefix" : { "full_name" : "joh" }
    }
}

wildcard

wildcard 指的是通配符查询。

支持的通配符主要有:

  • *:匹配 0 个或多个任意字符
  • ?:匹配 1 个任意字符
GET /user/_search
{
    "query": {
        "wildcard" : { "full_name" : "john*" }
    }
}

regexp

regexp 指的是正则查询。

GET /user/_search
{
    "query": {
        "regexp" : { "full_name" : "jo.*" }
    }
}

ids

ids 查询指的是根据文档的 id 来查询。

GET /user/_search
{
    "query": {
        "ids" : { "values" : ["1", "2", "60"] }
    }
}

复合查询

复合查询是将多个简单查询组合起来,实现更复杂的查询逻辑。

function_score

算分函数查询,可以人为控制文档的相关性评分,控制文档排名。如百度竞价排名。

  • query 简单查询语句,匹配的文档都有一个相关性评分 score
  • functions 算分函数,可对满足过滤条件的文档,额外计算一个分数
  • boost_mode 加权模式,指定两种分数的计算逻辑。如 sum, multiply

bool

bool 复合查询是将多个简单查询(子查询)进行组合。

组合的方式有以下几种:

  • must 必须匹配内部的每个子查询。类似 and。
  • should 匹配内部的任意一个子查询。类似 or。
  • must_not 必须不匹配。不进行相关性评分,类似取反。
  • filter 必须匹配。不进行相关性评分。

说明: must_not 和 filter 只进行条件过滤,不会参与评分,执行效率更高。对于评分没有要求的场景,尽量使用 must_not 和 filter

通常,全文搜索或需要用到相关性评分的场景采用 must 或 should,其他的全部用 filter

POST /user/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "last_name": "smith"
                    }
                }
            ],
            "should": [
                {
                    "term": {
                        "full_name": "john"
                    }
                },
                {
                    "term": {
                        "full_name": "smith"
                    }
                }
            ],
            "filter": [
                {
                    "term": {
                        "info.interests": "musics"
                    }
                }
            ],
            "must_not": [
                {
                    "range": {
                        "info.age": {
                            "gte": 10,
                            "lte": 25
                        }
                    }
                }
            ],
            "minimum_should_match": 1
        }
    }
}

查询与过滤

DSL 查询根据使用目的的不同分为两种类型:

  • 上下文查询(Query context),简称查询
  • 上下文过滤(Filter context),简称过滤

查询(Query)

在查询语境中,查询语句会判断文档是否匹配并计算相关性评分(_score)。

过滤(Filter)

过滤主要用于精确的字段查询。

例如:age 字段的值是否在 20-35 范围内?

一般来说,过滤语句比查询语句的执行效率更高,因为它不用计算文档的相关性评分(score)。

过滤语句的结果会被 ES 自动缓存,以提高性能。

过滤的目的就是粗暴地快速缩小匹配的结果集。

在进行搜索时,常常会在查询语句中,结合查询和过滤来达到我们的查询目的。

搜索结果处理

分页

ES 默认只会返回 top10 的文档。

可通过 from 和 size 参数实现分页查询。

sort 参数可实现自定义排序。

深度分页问题

ES 是分布式的,数据是分片存储的,在 ES 集群中,会面临深度分页问题。

如果搜索页数过深或者结果集(from + size)过大,对内存和 CPU 的影响就越大。

比如:每页 10 条,第 51 页就是,from=500, size=10。在 ES 集群中的实现是,先从每个分片上查询前 510 条,然后将所有节点的结果聚合,重新排序选出 510 条,最后从这 510 条数据中,选取最后的 10 条返回。

因此,ES 默认设定单机查询结果集的上限是 10000 条。也就是说 from + size <= 10000。

使用场景: 百度、京东的随机翻页搜索。

除了在业务侧进行强行限制外,针对深度分页问题,ES 也提供了一种解决方案。

search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。因此,它不支持随机翻页,只能向后翻页。

使用场景: 手机端的向下滚动翻页。

高亮

高亮:就是在搜索结果中把搜索关键字突出显示。

实现原理:

  • 由 ES 将搜索结果中的关键字用标签(默认是 <em></em>)包裹起来。可通过 highlight 参数实现。
  • 在前端页面中,给该标签添加 css 样式。
 类似资料: