ElasticSearch 模糊查询-脚本

本文介绍了ElasticSearch中实现模糊查询的三种方法:wildcard查询使用通配符进行匹配,regexp查询支持正则表达式,以及prefix查询针对前缀的检索。这些查询方式对于keyword类型的数据支持尤为有效。

ElasticSearch 模糊查询-脚本

模糊查询-脚本 的三种方法
wildcard查询:会对查询条件进行分词。还可以使用通配符? (任意单个字符)和* (0个或多个字符)

regexp查询?正则查询

prefix查询:前缀查询

wildcard查询

wildcard查询:会对查询条件进行分词。还可以使用通配符 ?(任意单个字符) 和 * (0个或多个字符)

"*华*"  包含华字的
"华*"   华字后边多个字符
"华?"  华字后边多个字符
"*华"或"?华" 会引发全表(全索引)扫描 注意效率问题
# wildcard 查询。查询条件分词,模糊查询
GET goods/_search
{
  "query": {
    "wildcard": {
      "title": {
        "value": "华*"
      }
    }
  }
}

正则查询

\W:匹配包括下划线的任何单词字符,等价于 [A-Z a-z 0-9_]   开头的反斜杠是转义符

+号多次出现

(.)*为任意字符
正则查询取决于正则表达式的效率
GET goods/_search
{
  "query": {
    "regexp": {
      "title": "\\w+(.)*"
    }
  }
}

前缀查询

对keyword类型支持比较好

# 前缀查询 对keyword类型支持比较好
GET goods/_search
{
  "query": {
    "prefix": {
      "brandName": {
        "value": "三"
      }
    }
  }
}

<think>我们正在处理用户关于在Elasticsearch中使用Painless脚本实现模糊查询的问题。 根据用户需求,我们需要提供一个Painless脚本的模糊查询示例。 注意:Elasticsearch的模糊查询通常通过查询DSL(如fuzzy query)实现,但用户明确要求使用Painless脚本。 然而,我们需要澄清:Painless脚本通常用于script query(脚本查询)或script_score查询中,而不是直接用于实现标准的模糊查询。 但是,我们可以通过脚本自定义相似度计算,比如使用Levenshtein距离或其他字符串相似度算法。 不过,请注意:在脚本中实现模糊匹配可能会影响性能,因为脚本计算是逐文档进行的,且不会利用倒排索引的优势。 因此,我们建议在可能的情况下优先使用Elasticsearch内置的fuzzy查询。但既然用户要求Painless脚本示例,我们将提供一个。 思路: 1. 使用Painless脚本计算两个字符串的Levenshtein编辑距离(或Damerau-Levenshtein距离)。 2. 设置一个阈值(最大编辑距离),当编辑距离小于等于该阈值时,认为匹配。 但是,在脚本查询中,我们需要返回一个布尔值(true/false)表示是否匹配。 注意:Levenshtein距离的计算在Painless中需要自己实现,因为Painless没有内置该函数。 我们将实现一个简单的Levenshtein距离计算函数,然后在脚本中调用。 示例场景:假设我们有一个字段"text_field",我们希望用脚本查询来模糊匹配用户输入的一个词(例如"kimchy",但可能拼写错误)。 步骤: 1. 在脚本中定义Levenshtein距离计算函数。 2. 比较文档字段值与用户输入的词的编辑距离。 3. 如果编辑距离小于等于指定的最大距离(如2),则返回true,否则false。 但是,请注意:如果字段是text类型且经过分析(例如分词),那么字段值可能是多个词项。而我们的模糊匹配通常针对单个词项。 因此,这个示例假设我们是在一个keyword类型的字段上操作(即整个字段作为一个字符串),或者我们针对的是text字段中的一个分词(这需要更复杂的处理,比如在脚本中访问该字段的terms集合,然后遍历每个词项)。 为了简化,我们假设字段是keyword类型(未分词),或者我们使用了一个未分词的子字段(如.keyword)。 示例脚本查询结构: ```json { "query": { "bool": { "filter": { "script": { "script": { "source": """ // 定义Levenshtein距离计算函数 int levenshtein(String s, String t) { int n = s.length(); int m = t.length(); // 如果其中一个长度为0,则返回另一个的长度(即需要插入所有字符) if (n == 0) return m; if (m == 0) return n; int[][] d = new int[n+1][m+1]; for (int i = 0; i <= n; i++) d[i][0] = i; for (int j = 0; j <= m; j++) d[0][j] = j; for (int i = 1; i <= n; i++) { char s_i = s.charAt(i-1); for (int j = 1; j <= m; j++) { char t_j = t.charAt(j-1); int cost = (s_i == t_j) ? 0 : 1; d[i][j] = Math.min( Math.min(d[i-1][j]+1, d[i][j-1]+1), d[i-1][j-1] + cost ); } } return d[n][m]; } // 获取文档字段值(假设字段名为'name',且为keyword类型) String fieldValue = doc['name.keyword'].value; // 用户输入的搜索词,这里用参数传递 String input = params.search_term; // 最大编辑距离 int maxDistance = params.max_distance; // 计算编辑距离 int distance = levenshtein(fieldValue, input); return distance <= maxDistance; """, "params": { "search_term": "kimchy", // 示例搜索词 "max_distance": 2 // 最大编辑距离 } } } } } } } ``` 注意:这个脚本查询会遍历所有文档,计算每个文档的字段值与搜索词的编辑距离,性能开销很大,不推荐在大数据集上使用。 替代方案:如果必须使用模糊查询,建议使用Elasticsearch内置的fuzzy查询,它会利用索引和倒排表,效率更高。例如: ```json { "query": { "fuzzy": { "name": { "value": "kimchy", "fuzziness": 2 } } } } ``` 但用户要求Painless脚本示例,所以我们提供了脚本方式。 另外,我们还可以考虑使用脚本在查询时对字段值进行模糊匹配,但同样要注意性能。 最后,我们生成相关问题。 相关问题: 1. 在Elasticsearch中使用Painless脚本进行模糊查询有哪些性能影响? 2. 除了Levenshtein距离,还有哪些字符串相似度算法可以在Painless脚本中实现? 3. 如何优化Painless脚本模糊查询的性能? 4. Elasticsearch内置的fuzzy查询与使用Painless脚本实现的模糊查询有何区别?</think>### Elasticsearch Painless脚本实现模糊查询示例 在Elasticsearch中,使用Painless脚本实现模糊查询需要结合脚本查询(`script_query`)和自定义的字符串相似度算法。以下是一个完整的示例,使用Levenshtein编辑距离实现模糊匹配: ```json GET /your_index/_search { "query": { "bool": { "filter": { "script": { "script": { "source": """ // 计算Levenshtein编辑距离 int levenshtein(String s, String t) { int n = s.length(); int m = t.length(); if (n == 0) return m; if (m == 0) return n; int[][] d = new int[n+1][m+1]; for (int i = 0; i <= n; i++) d[i][0] = i; for (int j = 0; j <= m; j++) d[0][j] = j; for (int i = 1; i <= n; i++) { char s_i = s.charAt(i-1); for (int j = 1; j <= m; j++) { char t_j = t.charAt(j-1); int cost = (s_i == t_j) ? 0 : 1; d[i][j] = Math.min( Math.min(d[i-1][j]+1, d[i][j-1]+1), d[i-1][j-1] + cost ); } } return d[n][m]; } // 获取字段值并比较 String fieldValue = doc[params.field].value; int distance = levenshtein(fieldValue, params.searchTerm); return distance <= params.maxDistance; """, "params": { "field": "title", // 目标字段名 "searchTerm": "kimchy", // 搜索词 "maxDistance": 2 // 最大允许编辑距离 } } } } } } } ``` #### 关键说明: 1. **算法原理**: - 使用Levenshtein编辑距离计算相似度,该算法衡量将一个字符串转换成另一个所需的最少单字符编辑(插入/删除/替换)次数[^3][^4] - 示例中`maxDistance=2`表示最多允许2个字符的差异 2. **参数说明**: - `field`:要搜索的目标字段(需为`keyword`类型) - `searchTerm`:用户输入的搜索词 - `maxDistance`:最大编辑距离阈值 3. **性能建议**: - 此方法会逐文档计算编辑距离,**不适用于大数据集** - 对高基数字段使用`script_score`查询替代`script`过滤,避免全量计算 - 建议结合`term`查询先做初步筛选: ```json "must": [{ "term": {"title.initial": {"value": "k"}} // 首字母过滤 }] ``` #### 替代方案(推荐): 对于生产环境,优先使用Elasticsearch内置的模糊查询,性能更优: ```json { "query": { "fuzzy": { "title": { "value": "kimchy", "fuzziness": "AUTO", // 自动根据词长确定容错 "transpositions": true // 允许相邻字符互换 } } } } ``` > ⚠️ **注意**:Painless脚本查询应作为最后手段,内置查询会利用Lucene索引优化,性能可提升10-100倍[^1][^3] --- ### 相关问题 1. 如何优化Painless脚本模糊查询的性能? 2. Levenshtein距离与Damerau-Levenshtein距离在模糊查询中有何区别? 3. Elasticsearch内置的`fuzzy`查询在底层如何利用索引加速? 4. 对于分词的text字段,如何实现基于分词的模糊匹配? 5. 在脚本查询中如何处理大小写敏感性问题? [^1]: Elasticsearch官方文档指出脚本查询应避免全量扫描,优先使用内置查询 [^3]: 模糊查询基于Levenshtein编辑距离实现,但内置查询会利用索引优化 [^4]: 实际应用中需注意脚本查询对集群性能的影响
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

普希托夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值