Эластичный поиск — Условная проекция

#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. Теперь я смирился с этим. Это не совсем то, что я искал по объясненным причинам, но я все равно приму, так как, похоже, реального решения того, что я хочу, нет 🙂