负前瞻Regexp在ES DSL查询中不起作用

时间:2018-08-10 09:23:21

标签: regex elasticsearch elasticsearch-dsl negative-lookbehind elasticsearch-dsl-py

Elastic搜索的映射如下:

{
  "settings": {
    "index": {
      "number_of_shards": "5",
      "number_of_replicas": "1"
    }
  },
  "mappings": {
    "node": {
      "properties": {
        "field1": {
          "type": "keyword"
        },
        "field2": {
          "type": "keyword"
        },
        "query": {
          "properties": {
            "regexp": {
              "properties": {
                "field1": {
                  "type": "keyword"
                },
                "field2": {
                  "type": "keyword"
                }
              }
            }
          }
        }
      }
    }
  }
}

问题是:

我正在使用elasticsearch_dsl Q()形成ES查询。当我的查询包含任何复杂的正则表达式时,它在大多数情况下都可以正常工作。但是,如果它包含正则表达式字符“!”,则它将完全失败。在里面。当搜索词包含“!”时,不会给出任何结果在里面。

例如:

1。)Q('regexp', field1 = "^[a-z]{3}.b.*")(效果很好)

2。)Q('regexp', field1 = "^f04.*")(效果很好)

3。)Q('regexp', field1 = "f00.*")(效果很好)

4。)Q('regexp', field1 = "f04baz?")(效果很好)

在以下情况下失败:

5。)Q('regexp', field1 = "f04((?!z).)*")(失败,完全没有结果)

我尝试在字段中如上所述添加“ analyzer”:“关键字”以及“ type”:“关键字”,但是在这种情况下没有任何作用。

在浏览器中,我尝试检查Analyzer:keyword在失败的情况下如何在输入上起作用:

http://localhost:9210/search/_analyze?analyzer=keyword&text=f04((?!z).) *

似乎在这里看起来很好,结果:

{
  "tokens": [
    {
      "token": "f04((?!z).)*",
      "start_offset": 0,
      "end_offset": 12,
      "type": "word",
      "position": 0
    }
  ]
}

我正在运行如下查询:

search_obj = Search(using = _conn, index = _index, doc_type = _type).query(Q('regexp', field1 = "f04baz?"))
count = search_obj.count()
response = search_obj[0:count].execute()
logger.debug("total nodes(hits):" + " " + str(response.hits.total))

请提供帮助,这确实是一个令人讨厌的问题,因为除!之外,所有正则表达式字符都可以在所有查询中正常工作。

还,如何检查映射中当前使用上述设置的分析仪?

1 个答案:

答案 0 :(得分:1)

ElasticSearch Lucene正则表达式引擎不支持任何类型的环视。 ES regex documentation的说法很matching everything like .* is very slow as well as using lookaround regular expressions含糊不清(这不仅含糊不清,而且还存在错误,因为明智地使用环视工具可能会大大加快正则表达式的匹配速度。)

由于您要匹配包含f04但不包含z的任何字符串,因此您实际上可以使用

[^z]*fo4[^z]*

详细信息

  • [^z]*-除z以外的任何0+个字符
  • fo4-fo4子字符串
  • [^z]*-z以外的任何0+个字符。

如果您有一个要排除的多字符字符串(例如,z4而不是z),则可以使用complement operator来使用您的方法:

.*f04.*&~(.*z4.*)

这意味着几乎相同,但不支持换行符:

  • .*-尽可能使用除换行符以外的任何字符
  • f04-f04
  • .*-尽可能使用除换行符以外的任何字符
  • &-和
  • ~(.*z4.*)-除具有z4的字符串以外的任何字符串