作者:来自 Elastic Justin Castilla
想要获得 Elastic 认证?看看下一次 Elasticsearch Engineer 培训什么时候开始吧!
Elasticsearch 拥有大量新功能,可以帮助你为你的使用场景构建最佳的搜索解决方案。深入了解我们的示例 notebooks,开始免费 cloud 试用,或立即在本地机器上体验 Elastic。
在 Elasticsearch 中,在字段中搜索包含特定子字符串的文档是一项常见需求。本文将探讨在 Elasticsearch 中进行查询的高级技巧,以找到字段中包含特定子字符串的文档。我们将讨论 query_string、match_phrase 和 wildcard 查询的使用,使用分析器和分词器来提高搜索准确性,以及可用于定位字段中子字符串的 ES|QL 函数。如果你想了解精确值与全文本的使用差异,请查看本指南。
1)query_string 查询
query_string 查询是一种强大且灵活的方式,用于搜索包含特定子字符串的文档。它允许你使用 Lucene 查询语法,提供了多种搜索选项。以下是一个 query_string 查询的示例,用于搜索包含子字符串 “example” 的文档:
GET /_search
{
"query": {
"query_string": {
"query": "*example*"
}
}
}
在这个示例中,星号( * )被用作通配符,匹配任意字符序列。query_string 查询会返回在任意字段中包含子字符串 “example” 的文档。但需要注意的是,前缀通配符可能会对你的集群性能产生负面影响。
2)match_phrase 查询
match_phrase 查询是另一种搜索包含特定子字符串文档的方式。它会在字段中搜索精确短语,并且可以配合 slop 参数使用,以允许单词顺序的变化。以下是一个 match_phrase 查询的示例,用于搜索包含子字符串 “quick brown” 的文档:
GET /_search
{
"query": {
"match_phrase": {
"field_name": "quick brown"
}
}
}
在这个示例中,match_phrase 查询会返回在指定字段中包含确切短语 “quick brown” 的文档。
3)wildcard 查询
wildcard 查询是一种简单的方式,用于搜索包含特定子字符串的文档。它使用通配符来匹配字段中任意字符序列。以下是一个 wildcard 查询的示例,用于搜索包含子字符串 “exam” 的文档:
GET /_search
{
"query": {
"wildcard": {
"field_name": "*exam*"
}
}
}
在这个示例中,wildcard 查询会返回在指定字段中包含子字符串 “exam” 的文档。在这种情况下,也需要特别注意在 wildcard 查询中使用前缀通配符,因为这可能会降低搜索性能。
4)分析器和分词器
为了提高子字符串搜索的准确性,你可以使用分析器和分词器来处理文档中的文本。分析器负责将文本分解成 token,这些 token 会用于索引和搜索。分词器是分析器的一个组件,用于将文本拆分为单个 token。
例如,你可以使用 n-gram 分词器从输入文本中创建不同长度的 token。这样可以通过匹配不同长度的子字符串来提高子字符串搜索的准确性。以下是一个使用 n-gram 分词器创建自定义分析器的示例:
PUT /my_index
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "ngram",
"min_gram": 3,
"max_gram": 5
}
}
}
}
}
在这个示例中,自定义分析器使用了一个 n-gram 分词器,其最小 token 长度为 3,最大 token 长度为 5。你可以在索引文档时以及进行子字符串搜索时使用这个自定义分析器。
需要注意的是,将大量文本分词为 n‑gram 会显著增加倒排索引中的 term 数量,从而不必要地增加存储,并降低索引和查询的速度。最好只对需要子字符串匹配的文本字段使用 n‑gram 分词器。
5)ES|QL 函数
LOCATE
ES|QL 的 LOCATE 函数用于查找文档中指定子字符串的首次出现位置。LOCATE 函数的调用方式如下:
这里,string 是要查询的字段,substring 是目标子字符串,start 是字符串中的整数偏移量。这个函数会返回从提供的 start 位置之后首次出现子字符串的位置的整数值;如果子字符串不存在,则返回 0。
对于字段中出现多次的子字符串,不建议使用这个函数,因为 ES|QL 中不支持迭代处理,它是一种纯声明式、流水线风格的查询语言。
MATCH
MATCH 函数会返回布尔值 true,如果传入 query 参数的子字符串出现在传入 field 参数的文本中。它适用于一般的全文搜索,相关性由术语是否存在决定,而不考虑它们的位置。
可选的命名函数参数可以传入以获得更细粒度的控制,比如模糊度( fuzziness )、用于解释文本的操作符,以及宽容度( leniency )值。
注意,查询中可以包含多个词项,结果可能包含这些词项中的任意一个,但不一定按给定顺序出现。
示例:搜索 “quick brown fox” 会匹配包含 “the fox is quick and brown” 的文档。
MATCH_PHRASE
MATCH_PHRASE 与 MATCH 函数类似,但它必须匹配传入函数的整个短语,而不是单个词项。它适用于你想搜索确切短语而不仅仅是单个词项是否存在的情况。
MATCH_PHRASE 也有可选的命名参数,允许各种细化设置,比如 slop 和 token 分析器。
示例:搜索 “quick brown fox” 只会匹配包含确切短语 “quick brown fox” 的文档。
KQL
KQL 查询指的是用 Kibana Query Language(KQL)编写的查询。KQL 是 Kibana 中使用的搜索和过滤语言,Kibana 是我们的数据可视化工具。Elastic 已将这种查询语言引入 ES|QL,以增强搜索功能。
示例:搜索 “foo: bar” AND “baz > 12” 会返回所有 “foo” 字段包含 “bar” 且 “baz” 字段值大于 12 的文档。
QSTR
QSTR 是 Lucene 使用的一种查询格式,提供对文本字段的灵活、基于相关性的搜索,类似于在 Elasticsearch DSL 中使用 match 查询。
示例:在工单索引中使用 QSTR 搜索 "timeout error OR "connection refused"",会返回包含 “timeout error” 或确切短语 “connection refused” 的工单文档。
QSTR 还提供最多的选项,能够在搜索中提供高度的粒度和灵活性。
附加内容:区间查询和跨度查询
区间查询 - interval queries
区间查询是搜索必须按照给定顺序出现的词项的查询。以下是一个示例查询:
POST _search
{
"query": {
"intervals" : {
"my_text" : {
"all_of" : {
"ordered" : true,
"intervals" : [
{
"match" : {
"query" : "it's rainy outside",
"max_gaps" : 0,
"ordered" : true
}
},
{
"any_of" : {
"intervals" : [
{ "match" : { "query" : "curl up with a good book" } },
{ "match" : { "query" : "listen to a podcast" } }
]
}
}
]
}
}
}
}
}
该查询搜索短语 “it’s rainy outside”,后面紧跟着 “curl up with a good book” 或 “listen to a podcast” 中的任意一个词项。
这句话会匹配:“When it’s rainy outside, I like to dress up in cozy clothes, turn on some classical music, and curl up with a good book.”
这句话不会匹配:“I find it best to listen to a podcast in my car when there’s a lot of traffic and it’s rainy outside.”
这是因为 “all_of”: {“ordered”: true} 条款,要求上述顺序必须严格遵守。
这是一个非常强大且可扩展的查询,适合用于动态且复杂的子字符串搜索。
跨度查询 - span
跨度查询通过操作 token 偏移量而非原始文本,提供了一种低级且带位置感知的子字符串搜索方法。跨度可以嵌套子跨度,这些子跨度必须满足诸如在指定距离内出现在另一个跨度之前或之后等约束条件。这使得它们非常适合处理某些领域(如法律文件),在这些领域中常见术语在靠近特定关键词时会获得特殊含义。
GET /_search
{
"query": {
"span_near": {
"clauses": [
{ "span_term": { "field": "contract" } },
{ "span_term": { "field": "breach" } }
],
"slop": 3,
"in_order": false
}
}
}
例如,你可以使用 span_near 查询来查找距离 “breach” 四个 token 以内的 “contract”。一份冗长的法律摘要中可能多次提到 “contract”,但只有两个地方出现了短语 “breach of obligation and contract” 或 “breach of contract litigation”。通过调整跨度距离(例如 slop: 3),你只会匹配这两个上下文,忽略所有其他的 “contract” 出现。
总结
Elasticsearch 提供了多种高级技术,用于查询包含特定子字符串的文档。通过使用 query_string、match_phrase 和 wildcard 查询,自定义分析器和分词器,ES|QL 函数,甚至是区间查询或跨度查询,你可以提高子字符串搜索的准确性和灵活性。尝试这些技术,找到最适合你具体用例和数据集的方法。
原文:https://www.elastic.co/search-labs/blog/elasticsearch-string-contains-substring