Как в фильтре поиска проверять размер поля?

Имеется ElasticSearch 7.3.2
Внутри него есть индекс с полем "message" типа "text".

Пытаюсь найти в нём документы, в которых поле имеет большую длину:

curl -XPOST -H 'Content-Type: application/json' -d '
{
  "query": {
    "bool": {
      "filter": {
        "script": {
          "script": {
            "source": "doc['message'].toString().length() > 10000,
            "lang": "painless"
          }
        }
      }
    }
  },
  "script_fields": {
    "A": { "script": { "lang": "painless", "source": "params._source.message.toString().length()" } },
    "B": { "script": { "lang": "painless", "source": "doc['message'].toString().length()" } },
    "C": { "script": { "lang": "painless", "source": "doc['message'].length" } },
    "D": { "script": { "lang": "painless", "source": "doc['message'].size()" } }
  }
}
' "127.0.0.1:9200/myindex/_search?pretty=true"

Результат:

"fields" : {
  "A" : [ 2155780 ],
  "B" : [ 13206 ],
  "D" : [ 1514 ],
  "C" : [ 1514 ]
}

Верное значение содержится только в поле "A". Но его невозможно использовать для поиска, потому что query filter не знает про _source.

Вопросы:

  1. Что содержат значения B и C? Почему значения A,B,C разные?
  2. Как узнать размер поля в query filter?

Что содержат значения B и C? Почему значения A,B,C разные?

A - содержит размер исходной строки
B - содержит в себе список всех уникальных токенов (слов) в алфавитном порядке. То есть, если исходная строка была Что в лоб, что по лбу то мы будем считать длину строки [в, лбу, лоб, по, что] в случае стандартного анилизатора или [лбу, лоб], если анализатор удаляет русские шумовые слова.
C - это размер массива, про который мы рассматривали в B
D - тоже, что и C

Как узнать размер поля в query filter?

Во время выполнения запроса, это информация недоступна так как она отсутствует в индексе. Нужно либо переиндексировать, либо делать update_by_query по всему индексу.

Какой конечный результат нужен?

Какой конечный результат нужен?

Список _docid и размеров для документов, поле message в которых занимает больше мегабайта (и поэтому Кибана отказывается с ними работать).

В SQL это выглядело бы так:

delete from myIndex where length(message) > 1000000;

Сейчас делаю для этого полный перебор индекса:

curl -XPOST -H 'Content-Type: application/json' -sS -d '
{
    "from" : 0,
    "size" : 10000,
    "query": { "match_all": {} },
    "script_fields": {
        "A": { "script": { "lang": "painless", "source": "params._source.message.toString().length()" } }
    }
}
' "127.0.0.1:9200/myIndex/_search?pretty=true" |
jq -jr '.hits.hits[] | ._id, " ", .fields.A[0], "\n"' |
while read docid sz; do
    test "$sz" -ge 500000 && curl -sS -XDELETE "127.0.0.1:9200/myIndex/_doc/$docid?pretty=true"
done

В качестве временного решения такой вариант меня устраивает, но на будущее хотелось бы разобраться.

На будущее, я бы пропустил записи через ingest processor при индексировании и добавил бы размер поля, как отдельное поле. А можно еще оставить в поле только первые 100000 символов, или не индексировать запись вообще.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.