Имеется 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.
Вопросы:
- Что содержат значения B и C? Почему значения A,B,C разные?
- Как узнать размер поля в 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 символов, или не индексировать запись вообще.