Как выделить вложенные поля в Elasticsearch
хотя введение логическая структура, я пытаюсь сделать мой вложенные поля будет выделен, когда некоторый результат поиска присутствует в их содержимом.
вот объяснение от документация Elasticsearch (отображение вложенного типа`)
Внутри
внутренне вложенные объекты индексируются как дополнительные документы, но, поскольку они могут быть гарантированы индексированный в том же" блоке", он позволяет очень быстро объединяться с родительскими документами.
эти внутренние вложенные документы автоматически маскируются при выполнении операций с индексом (например, поиск с запросом match_all), и они всплывают при использовании вложенного запроса.
поскольку вложенные документы всегда маскируются для родительского документа, вложенные документы никогда не могут быть доступны за пределами области вложенного запроса. Например, можно включить сохраненные поля на полях внутри вложенных объектов, но нет способа их извлечения, так как сохраненные поля извлекаются за пределами области вложенного запроса.
0. В моем случае
у меня есть Elasticsearch содержащий картография следующим образом:
{
"my_documents": {
"dynamic_date_formats": [
"dd.MM.yyyy",
"yyyy-MM-dd",
"yyyy-MM-dd HH:mm:ss"
],
"index_analyzer": "Analyzer2_index",
"search_analyzer": "Analyzer2_search_decompound",
"_timestamp": {
"enabled": true
},
"properties": {
"identifier": {
"type": "string"
},
"description": {
"type": "multi_field",
"fields": {
"sort": {
"type": "string",
"index": "not_analyzed"
},
"description": {
"type": "string"
}
}
},
"files": {
"type": "nested",
"include_in_root": true,
"properties": {
"content": {
"type": "string",
"include_in_root": true
}
}
},
"and then some other": "normal string fields"
}
}
}
Я пытаюсь выполнить такой запрос:
{
"size": 100,
"query": {
"bool": {
"should": [
{
"nested": {
"path": "files",
"query": {
"bool": {
"should": {
"match": {
"content": {
"query": "burpcontrol",
"minimum_should_match": "85%"
}
}
}
}
}
}
},
{
"match": {
"description": {
"query": "burpcontrol",
"minimum_should_match": "85%"
}
}
},
{
"match": {
"identifier": {
"query": "burpcontrol",
"minimum_should_match": "85%"
}
}
} ]
}
},
"highlight": {
"pre_tags": [
"<span style="background-color: yellow">"
],
"post_tags": [
"</span>"
],
"order": "score",
"no_match_size": 100,
"fragment_size": 50,
"number_of_fragments": 3,
"require_field_match": true,
"fields": {
"files.content": {},
"description": {},
"identifier": {}
}
}
}
проблема у меня есть:
1. require_field_match
если я использую "require_field_match": false
Я получаю это, даже если выделение не работает на вложенных полях, поисковый термин все равно выделяется в все поля.
Это решение, которое я на самом деле использую, но выступления ужасны. Для 50 документов мой запрос должен 25 сек. 100 документы о 50secs. 10 5secs документов.
и если я удалю вложенное поле из подсветки, все будет работать быстро, как свет!
2 .include_in_root
Я хотел бы иметь уплощена версии вложенные поля (поэтому хранить их как обычные объекты/поля. Для этого я должен указать
"files": {"type": "вложенные","include_in_root": правда, ...
но я не знаю, почему после переиндексации я не вижу дополнительного сплющенного поля в корне документа (в то время как я ожидал чего-то вроде "files.content":["content1", "content2", "..."]
).
если он будет работать он вместо этого можно было бы получить доступ (в сплющенном поле) к содержимому вложенного поля и выполнить выделение на нем.
вы знаете, если это возможно достичь хорошей (и эффективной) подсветки вложенных полей или, по крайней мере, предложить мне почему мой запрос так медленно? (Я уже оптимизировал фрагменты)
1 ответов
есть ряд вещей, которые вы можете сделать здесь, с отношениями родитель / ребенок. Я пройдусь по нескольким, и, надеюсь, это приведет вас в правильном направлении; все равно потребуется много тестов, чтобы выяснить, будет ли это решение более эффективным для вас. Кроме того, я опустил некоторые детали вашей установки, для ясности. Простите за длинный пост.
Я настроил отображение родителя / ребенка следующим образом:
DELETE /test_index
PUT /test_index
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"parent_doc": {
"properties": {
"identifier": {
"type": "string"
},
"description": {
"type": "string"
}
}
},
"child_doc": {
"_parent": {
"type": "parent_doc"
},
"properties": {
"content": {
"type": "string"
}
}
}
}
}
затем добавлен некоторый тест docs:
POST /test_index/_bulk
{"index":{"_index":"test_index","_type":"parent_doc","_id":1}}
{"identifier": "first", "description":"some special text"}
{"index":{"_index":"test_index","_type":"child_doc","_parent":1}}
{"content":"text that is special"}
{"index":{"_index":"test_index","_type":"child_doc","_parent":1}}
{"content":"text that is not"}
{"index":{"_index":"test_index","_type":"parent_doc","_id":2}}
{"identifier": "second", "description":"some different text"}
{"index":{"_index":"test_index","_type":"child_doc","_parent":2}}
{"content":"different child text, but special"}
{"index":{"_index":"test_index","_type":"parent_doc","_id":3}}
{"identifier": "third", "description":"we don't want this parent"}
{"index":{"_index":"test_index","_type":"child_doc","_parent":3}}
{"content":"or this child"}
если я правильно понимаю ваши спецификации, мы хотели бы запрос "special"
вернуть все эти документы, кроме последних двух (поправьте меня, если я ошибаюсь). Мы хотим, чтобы документы соответствовали тексту, имели ребенка, который соответствует тексту, или родителя, который соответствует тексту.
мы можем вернуть родителей, которые соответствуют запросу следующим образом:
POST /test_index/parent_doc/_search
{
"query": {
"match": {
"description": "special"
}
},
"highlight": {
"fields": {
"description": {},
"identifier": {}
}
}
}
...
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.1263815,
"hits": [
{
"_index": "test_index",
"_type": "parent_doc",
"_id": "1",
"_score": 1.1263815,
"_source": {
"identifier": "first",
"description": "some special text"
},
"highlight": {
"description": [
"some <em>special</em> text"
]
}
}
]
}
}
и мы можем вернуть детей, которые соответствуют запросу, как это:
POST /test_index/child_doc/_search
{
"query": {
"match": {
"content": "special"
}
},
"highlight": {
"fields": {
"content": {}
}
}
}
...
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.92364895,
"hits": [
{
"_index": "test_index",
"_type": "child_doc",
"_id": "geUFenxITZSL7epvB568uA",
"_score": 0.92364895,
"_source": {
"content": "text that is special"
},
"highlight": {
"content": [
"text that is <em>special</em>"
]
}
},
{
"_index": "test_index",
"_type": "child_doc",
"_id": "IMHXhM3VRsCLGkshx52uAQ",
"_score": 0.80819285,
"_source": {
"content": "different child text, but special"
},
"highlight": {
"content": [
"different child text, but <em>special</em>"
]
}
}
]
}
}
мы можем вернуть родителей, которые соответствуют тексту, и детей, которые соответствуют тексту, как это:
POST /test_index/parent_doc,child_doc/_search
{
"query": {
"multi_match": {
"query": "special",
"fields": ["description", "content"]
}
},
"highlight": {
"fields": {
"description": {},
"identifier": {},
"content": {}
}
}
}
...
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1.1263815,
"hits": [
{
"_index": "test_index",
"_type": "parent_doc",
"_id": "1",
"_score": 1.1263815,
"_source": {
"identifier": "first",
"description": "some special text"
},
"highlight": {
"description": [
"some <em>special</em> text"
]
}
},
{
"_index": "test_index",
"_type": "child_doc",
"_id": "geUFenxITZSL7epvB568uA",
"_score": 0.75740534,
"_source": {
"content": "text that is special"
},
"highlight": {
"content": [
"text that is <em>special</em>"
]
}
},
{
"_index": "test_index",
"_type": "child_doc",
"_id": "IMHXhM3VRsCLGkshx52uAQ",
"_score": 0.6627297,
"_source": {
"content": "different child text, but special"
},
"highlight": {
"content": [
"different child text, but <em>special</em>"
]
}
}
]
}
}
однако, чтобы вернуть все документы, связанные с этим запросом, нам нужно использовать bool
запрос:
POST /test_index/parent_doc,child_doc/_search
{
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "special",
"fields": [
"description",
"content"
]
}
},
{
"has_child": {
"type": "child_doc",
"query": {
"match": {
"content": "special"
}
}
}
},
{
"has_parent": {
"type": "parent_doc",
"query": {
"match": {
"description": "special"
}
}
}
}
]
}
},
"highlight": {
"fields": {
"description": {},
"identifier": {},
"content": {}
}
},
"fields": ["_parent", "_source"]
}
...
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 5,
"max_score": 0.8866254,
"hits": [
{
"_index": "test_index",
"_type": "parent_doc",
"_id": "1",
"_score": 0.8866254,
"_source": {
"identifier": "first",
"description": "some special text"
},
"highlight": {
"description": [
"some <em>special</em> text"
]
}
},
{
"_index": "test_index",
"_type": "child_doc",
"_id": "geUFenxITZSL7epvB568uA",
"_score": 0.67829096,
"_source": {
"content": "text that is special"
},
"fields": {
"_parent": "1"
},
"highlight": {
"content": [
"text that is <em>special</em>"
]
}
},
{
"_index": "test_index",
"_type": "child_doc",
"_id": "IMHXhM3VRsCLGkshx52uAQ",
"_score": 0.18709806,
"_source": {
"content": "different child text, but special"
},
"fields": {
"_parent": "2"
},
"highlight": {
"content": [
"different child text, but <em>special</em>"
]
}
},
{
"_index": "test_index",
"_type": "child_doc",
"_id": "NiwsP2VEQBKjqu1M4AdjCg",
"_score": 0.12531912,
"_source": {
"content": "text that is not"
},
"fields": {
"_parent": "1"
}
},
{
"_index": "test_index",
"_type": "parent_doc",
"_id": "2",
"_score": 0.12531912,
"_source": {
"identifier": "second",
"description": "some different text"
}
}
]
}
}
(Я включил "_parent"
поле, чтобы было проще понять, почему документы были включены в результаты, как показано здесь).
Дайте мне знать, если это помогает.
вот код I используется:
http://sense.qbox.io/gist/d69a4d6531dc063faa4b4e094cff2a472a73c5a6