Terms-level Query之Prefix Query

​在本文开始之前,引入一个问题:如何在索引中某个字段上查找以FD为前缀所有商品?Prefix Query 前缀匹配检索解决类似问题。

Prefix Query属于Term-level Query查询,查找索引中指定的字段上满足指定前缀的文档。类似关系型数据库,如MySQL中Like查询最左匹配原则。脑图如下:

内容说明:

本文内容同微信公众号【凡登】,关注不迷路,学习上高速,欢迎关注共同学习。原文链接:

Terms-level Query之Prefix Query

目录

一、语法

二、参数查询示例

1、默认参数查询

2、case_insensitive 参数

3、rewrite 参数

三、利用index_prefixes加速查询

四、开启expensive_queries查询

五、总结


本文基于Elasticsearch 7.13 版本。官方文档

https://www.elastic.co/guide/en/elasticsearch/reference/7.10/query-dsl-prefix-query.html

一、语法

GET _search{  "query":{    "prefix": {      "<field>": {  // 待查询字段          "value": "前缀字符",          "case_insensitive":false,          "rewrite":"constant_score"      }    }  }}# 简写查询语法GET _search{  "query":{    "prefix": { "<field>": "前缀字符" }  }}

参数说明:

  • "value": 待查询的前缀值  必填

  • "case_insensitive": 是否大小写敏感, 默认 false ,即大小写敏感, 非必填

  • "rewrite": 仅专业用户配置使用,默认constant_score,非必填

二、参数查询示例

# 样例数据POST prefix_query_demo_index/_bulk{"index":{}}{"name":"deng"}{"index":{}}{"name":"Deng"}{"index":{}}{"name":"fandeng"}{"index":{}}{"name":"FanDeng"}#mapping结构如下{  "prefix_query_demo_index" : {    "mappings" : {      "properties" : {        "name" : {          "type" : "keyword" // 类型为keyword        }      }    }  }}

1、默认参数查询

GET prefix_query_demo_index/_search{  "query":{    "prefix": {      "name": {        "value": "d"      }    }  }}结果:结果仅显示以d为前缀的文档,忽略大写D,即大小写敏感{    // 省略    "hits" : [      {        "_index" : "prefix_query_demo_index",        "_type" : "_doc",        "_id" : "vnEDjYAB3Oxj0n4YCSWj",        "_score" : 1.0,        "_source" : {          "name" : "deng"        }      }    ]}

2、case_insensitive 参数

忽略大小写检索。于Elasticsearch 7.10.0 引入。

GET prefix_query_demo_index/_search{  "query":{    "prefix": {      "name": {        "value": "d",        "case_insensitive":true      }    }  }}结果:结果显示以d和D为前缀的文档,忽略大小写{    // 省略    "hits" : [      {        "_index" : "prefix_query_demo_index",        "_type" : "_doc",        "_id" : "vnEDjYAB3Oxj0n4YCSWj",        "_score" : 1.0,        "_source" : {          "name" : "deng"        }      },      {        "_index" : "prefix_query_demo_index",        "_type" : "_doc",        "_id" : "wXEDjYAB3Oxj0n4YCSWj",        "_score" : 1.0,        "_source" : {          "name" : "Deng"        }      }    ]  }}

3、rewrite 参数

由于elasticsearch底层不支持prefix query,需要将其转换为bool以及term组合查询以期达到与prefix query同样的效果,转换有多种方式,此项提供了可选择的转换方式 默认 constant_score , 非必填。其他有效值设置,可参见:

https://www.elastic.co/guide/en/elasticsearch/reference/7.13/query-dsl-multi-term-rewrite.html

三、利用index_prefixes加速查询

prefix query查询性能较差,且影响集群文档性,为text字段添加index_prefixes参数可提高检索效率。官方文档:

https://www.elastic.co/guide/en/elasticsearch/reference/7.10/index-prefixes.html

示例如下:

# 定义mappingPUT prefix_query_demo_index{  "mappings": {    "properties": {      "name":{        "type": "text",        "index_prefixes":{          "min_chars" : 2, // 最小的前缀长度,大于0,默认2          "max_chars" : 5 // 最大的前缀长度,小于20,默认5        }      }    }  }}以下示例与上述mapping定义示例效果相同PUT prefix_query_demo_index{  "mappings": {    "properties": {      "name":{        "type": "text", // 类型为        "index_prefixes":{}      }    }  }}

验证:

GET prefix_query_demo_index/_search{  "query":{    "prefix": {      "name": {        "value": "fande" // 前缀字符串长度必须2~5,否则报错      }    }  }}结果:{    // 省略    "hits" : [      {        "_index" : "prefix_query_demo_index",        "_type" : "_doc",        "_id" : "8vb3o4ABUfwYCvQ_kwUU",        "_score" : 1.0,        "_source" : {          "name" : "fandeng"        }      },      {        "_index" : "prefix_query_demo_index",        "_type" : "_doc",        "_id" : "9fb3o4ABUfwYCvQ_kwUU",        "_score" : 1.0,        "_source" : {          "name" : "FanDeng"        }      }    ]}

注:"value": "fande" // 因为当前name字段类型为text,此时字符长度必须2~5,否则报错。如果字段类型为keyword则无长度限制

问题:上述prefix查询默认大小写敏感,但为什么结果可以匹配到name值为大写的FanDeng 呢?我们再来看一个例子。

GET prefix_query_demo_index/_search{  "query":{    "prefix": {      "name": {        "value": "Fande"      }    }  }}结果:{  "took" : 0,  "timed_out" : false,  "_shards" : {    "total" : 1,    "successful" : 1,    "skipped" : 0,    "failed" : 0  },  "hits" : {    "total" : {      "value" : 0,      "relation" : "eq"    },    "max_score" : null,    "hits" : [ ]  }}

为什么没匹配文档?

因为当前name字段为text类型,在索引过程中将name字段中的值全部转为小写后再索引,而prefix前缀查询在区分大小写下就无法匹配到符合条件的文档;

四、开启expensive_queries查询

Prefix Query查询过程比较慢且影响集群稳定性,expensive_queries配置可控制此类查询是否在集群中执行。如果字段开启index_prefixes属性,则忽略该设置。

# 关闭expensive_queries查询PUT _cluster/settings{  "persistent":{    "search.allow_expensive_queries": false  }}# 结果:{  "acknowledged" : true,  "persistent" : {    "search" : {      "allow_expensive_queries" : "false"    }  },  "transient" : { }}

开始验证

# 验证:GET prefix_query_demo_index/_search{  "query": {    "prefix": {      "name": "d"    }  }}# 结果报错:{  "error" : {    "root_cause" : [      {        "type" : "exception",        "reason" : "[prefix] queries cannot be executed when 'search.allow_expensive_queries' is set to false. For optimised prefix queries on text fields please enable [index_prefixes]."      }    ],    "type" : "search_phase_execution_exception",    "reason" : "all shards failed",    "phase" : "query",    "grouped" : true,    "failed_shards" : [      // 省略      }    ],    "caused_by" : {      "type" : "exception",      "reason" : "[prefix] queries cannot be executed when 'search.allow_expensive_queries' is set to false. For optimised prefix queries on text fields please enable [index_prefixes]."    }  },  "status" : 400}

五、总结

Prefix Query查询需要注意几点:

1、前缀字符大小写敏感

2、如开启index_prefixs属性,

    2.1、字段类型必须为text

    2.2、尽量采用小写作为前缀字符串进行查询。

    2.3、前缀字符串长度一定控制在min_chars和max_chars之间,否则报错。

    2.4、忽略集群expensive_queries配置。

3、Prefix Query查询开销较大且影响集群稳定性,可通过expensive_queries配置控制Prefix Query检索。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值