ElasticSearch和Regex查询

aeu*_*ere 11 regex elasticsearch

我试图查询在"内容"字段的正文中具有日期的文档.

curl -XGET 'http://localhost:9200/index/_search' -d '{
    "query": {
        "regexp": {
            "content": "^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\\d\\d)$" 
            }
        }
    }'
Run Code Online (Sandbox Code Playgroud)

越来越近了吗?

curl -XGET 'http://localhost:9200/index/_search' -d '{
        "filtered": {
        "query": {
            "match_all": {}
        },
        "filter": {
            "regexp":{
                "content" : "^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.]((19|20)\\d\\d)$"
                }
            }
        }
    }'
Run Code Online (Sandbox Code Playgroud)

我的正则表达式似乎已经关闭了.此正则表达式已在regex101.com上验证.以下查询仍然不返回我拥有的175k文档.

curl -XPOST 'http://localhost:9200/index/_search?pretty=true' -d '{
        "query": {
            "regexp":{
                "content" : "/[0-9]{4}-[0-9]{2}-[0-9]{2}|[0-9]{2}-[0-9]{2}-[0-9]{4}|[0-9]{2}/[0-9]{2}/[0-9]{4}|[0-9]{4}/[0-9]{2}/[0-9]{2}/g"
            }
        }
    }'
Run Code Online (Sandbox Code Playgroud)

我开始认为我的索引可能没有为这样的查询设置.您必须使用哪种类型的字段才能使用正则表达式?

mappings: {
    doc: {
        properties: {
            content: {
                type: string
            }title: {
                type: string
            }host: {
                type: string
            }cache: {
                type: string
            }segment: {
                type: string
            }query: {
                properties: {
                    match_all: {
                        type: object
                    }
                }
            }digest: {
                type: string
            }boost: {
                type: string
            }tstamp: {
                format: dateOptionalTimetype: date
            }url: {
                type: string
            }fields: {
                type: string
            }anchor: {
                type: string
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我想找到任何有日期和记录该日期之前的文档量的记录.第1步是让这个查询工作.第2步将拉出日期并相应地将它们分组.有人可以建议一种方法来使第一部分工作,因为我知道第二部分将是非常棘手的.

谢谢!

fem*_*gon 27

您应该仔细阅读Elasticsearch的Regexp查询文档,对正则表达式查询的工作方式做出一些不正确的假设.

在这里要理解的最重要的事情可能是你要匹配的字符串是什么.您正在尝试匹配术语,而不是整个字符串.如果使用StandardAnalyzer对其进行索引,我怀疑,您的日期将分为多个术语:

  • "01/01/1901"成为令牌"01","01"和"1901"
  • "01 01 1901"成为代币"01","01"和"1901"
  • "01-01-1901"成为令牌"01","01"和"1901"
  • "01.01.1901"实际上将是一个单一的标记:"01.01.1901"(由于十进制处理,请参阅UAX#29)

您只能将单个整个令牌与正则表达式查询匹配.

Elasticsearch(和lucene)不支持完全与Perl兼容的正则表达式语法.

在你的第一对夫妇的例子,您使用的锚,^$.这些不受支持.你的正则表达式必须匹配整个令牌以获得匹配,所以不需要锚点.

也不支持像\d(或\\d)这样的速记字符类.而不是\\d\\d,使用[0-9]{2}.

在您上次尝试中,您正在使用/{regex}/g,但也不受支持.由于正则表达式需要匹配整个字符串,因此全局标志在上下文中甚至没有意义.除非您使用的是使用它们来表示正则表达式的查询解析器,否则您的正则表达式不应该用斜杠包装.

(顺便说一下:这个如何在regex101上验证?你有一堆未转义的/s.当我尝试时,它会向我抱怨.)


为了在这样的分析字段上支持这种查询,您可能希望查看跨度查询,特别是Span MultitermSpan Near.也许是这样的:

{
    "span_near" : {
        "clauses" : [
            { "span_multi" : { 
                "regexp": {
                    "content": "0[1-9]|[12][0-9]|3[01]" 
                }
            },
            { "span_multi" : { 
                "regexp": {
                    "content": "0[1-9]|1[012]" 
                }
            },
            { "span_multi" : { 
                "regexp": {
                    "content": "(19|20)[0-9]{2}" 
                }
            }
        ],
        "slop" : 0,
        "in_order" : true
    }
}
Run Code Online (Sandbox Code Playgroud)