Запросы ElasticSearch и Regex

Я пытаюсь запросить документы, содержащие даты в теле поля "контент".

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)$" 
            }
        }
    }'

Как можно ближе?

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)$"
                }
            }
        }
    }'

Мое регулярное выражение, похоже, отключено. Это регулярное выражение проверено на 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"
            }
        }
    }'

Я начинаю думать, что мой индекс не может быть настроен для такого запроса. Какой тип поля вы должны использовать, чтобы иметь возможность использовать регулярные выражения?

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
            }
        }
    }

Я хочу найти любую запись, у которой есть дата и график объема документов к этой дате. Шаг 1. должен заставить этот запрос работать. Шаг 2. будет вытягивать даты и группировать их соответственно. Может кто-то предложить способ, чтобы первая часть работала, поскольку я знаю, что вторая часть будет действительно сложной.

Спасибо!

Ответ 1

Вы должны внимательно прочитать Elasticsearch Regexp Query documentation, вы делаете некоторые неправильные предположения о том, как работает запрос 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)

Вы можете сопоставить только один цельный токен с запросом regexp.

Elasticsearch (и lucene) не поддерживают полный синтаксис regex, совместимый с Perl.

В ваших первых двух примерах вы используете привязки, ^ и $. Они не поддерживаются. Ваше регулярное выражение должно соответствовать всем токенам, чтобы получить соответствие в любом случае, поэтому привязки не нужны.

Сокращенные классы символов, такие как \d (или \\d), также не поддерживаются. Вместо \\d\\d используйте [0-9]{2}.

В вашей последней попытке вы используете /{regex}/g, который также не поддерживается. Поскольку ваше регулярное выражение должно соответствовать всей строке, глобальный флаг не имеет смысла даже в контексте. Если вы не используете синтаксический анализатор запросов, который использует их для обозначения регулярного выражения, ваше регулярное выражение не должно быть обернуто косой чертой.

(Кстати: как это подтвердилось в regex101? У вас есть группа unescaped / s. Она жалуется на меня, когда я пытаюсь.)


Чтобы поддерживать такой запрос в таком анализируемом поле, вы, вероятно, захотите посмотреть на запросы запросов, в частности Span Multiterm и Расстояние около. Возможно, что-то вроде:

{
    "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
    }
}