#elasticsearch
Вопрос:
Я знаю, что мы можем использовать проекцию в эластичном поиске, чтобы влиять на то, какие поля документа возвращаются или нет — аналогично проекции в других областях. Однако могу ли я также выполнить проекцию таким образом, чтобы поля — или, в моем случае, что более важно, элементы массива — отфильтровывались, если они не соответствуют определенному условию?
Допустим, документы, проиндексированные в ES, выглядят следующим образом:
{
"identificationString": "XYZ-123",
"localElements": [{
"name": "table",
"languageCode": "en"
}, {
"name": "mesa",
"languageCode": "es"
}],
"author": "Jon Snow",
"department": "Wood Work"
}
Для создания этого индекса я использовал, например:
curl -X PUT "localhost:9200/my-index?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"identificationString": {
"type": "text"
},
"localElements": {
"type": "nested",
"properties": {
"name": { "type": "text" },
"languageCode": { "type": "text" }
}
},
"author": {
"type": "text"
},
"department": {
"type": "text"
},
}
}
}
'
Для индексации вышеупомянутого документа я использовал:
curl -X POST "localhost:9200/my-index/_doc/?pretty" -H 'Content-Type: application/json' -d'
{
"identificationString": "XYZ-123",
"localElements": [{
"name": "table",
"languageCode": "en"
}, {
"name": "mesa",
"languageCode": "es"
}],
"author": "Jon Snow",
"department": "Wood Work"
}
'
Если я только захочу вернуться, например identificationString
, и localElements
я смогу сделать это так:
curl -X GET "localhost:9200/my-index/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
},
"fields": ["identificationString", "localElements.*"],
"_source": false
}
'
'
или что-то в этом роде:
curl -X GET "localhost:9200/my-index/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
},
"_source": ["identificationString", "localElements.*"]
}
'
Однако существует ли также способ вернуть только те локальные элементы, которые удовлетворяют определенному условию? например, только те, у которых есть определенный languageCode
? Я хотел бы отфильтровать те элементы, которые не удовлетворяют определенному условию — я не хочу видеть их в ответе. Конечно, я мог бы выполнить эту логику в самом приложении, но мне было интересно, может ли эластичный поиск сделать то же самое?
Ответ №1:
Вы можете использовать inner_hits вместе с вложенным запросом
{
"query": {
"nested": {
"path": "localElements",
"query": {
"bool": {
"must": {
"match": {
"localElements.languageCode": "es"
}
}
}
},
"inner_hits": {}
}
}
}
Результатом поиска будет
"hits": [
{
"_index": "67805874",
"_type": "_doc",
"_id": "1",
"_score": 0.6931471,
"_source": {
"identificationString": "XYZ-123",
"localElements": [
{
"name": "table",
"languageCode": "en"
},
{
"name": "mesa",
"languageCode": "es"
}
],
"author": "Jon Snow",
"department": "Wood Work"
},
"inner_hits": {
"localElements": {
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "67805874",
"_type": "_doc",
"_id": "1",
"_nested": {
"field": "localElements",
"offset": 1
},
"_score": 0.6931471,
"_source": {
"name": "mesa",
"languageCode": "es" // note this
}
}
]
}
}
}
}
]
Комментарии:
1. Это выглядит довольно многообещающе. Это может сработать для моего варианта использования. Я проведу дальнейшее расследование, а затем вернусь к вам.
2. @KarlMeierBE вы пробовали использовать bu
inner_hits
? Пожалуйста, дайте мне знать, сработало ли это для вас ?3. Похоже, это вроде как работало, да. Это не совсем то поведение, которое я хотел бы иметь, так как тогда вам нужно проанализировать внутренние хиты и разобраться с ними определенным образом. Я бы предпочел, если бы я мог сделать условную проекцию и просто вернуть документ с соответствующим полем напрямую. Я немного подожду, чтобы посмотреть, найдет ли кто — нибудь еще способ достичь этого, а если нет-я приму ваш ответ в качестве решения
4. Теперь я смирился с этим. Это не совсем то, что я искал по объясненным причинам, но я все равно приму, так как, похоже, реального решения того, что я хочу, нет 🙂