Агрегация Elasticsearch переводит результаты в нижний регистр

Я немного поиграл с ElasticSearch и обнаружил проблему при агрегировании.

У меня две конечные точки: / A и / B. В первом у меня есть родители для второго. Таким образом, один или несколько объектов в B должны принадлежать одному объекту в A. Следовательно, объекты в B имеют атрибут «parentId» с родительским индексом, созданным ElasticSearch.

Я хочу отфильтровать родителей в A по дочерним атрибутам B. Для этого я сначала фильтрую детей в B по атрибутам и получаю их уникальные родительские идентификаторы, которые позже буду использовать для получения родителей.

Отправляю такой запрос:

POST http://localhost:9200/test/B/_search
{
    "query": {
        "query_string": {
            "default_field": "name",
            "query": "derp2*"
        }
    },
    "aggregations": {
        "ids": {
            "terms": {
                "field": "parentId"
            }
        }
    }
}

И получите такой ответ:

{
  "took": 91,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 1,
    "hits": [
      {
        "_index": "test",
        "_type": "child",
        "_id": "AU_fjH5u40Hx1Kh6rfQG",
        "_score": 1,
        "_source": {
          "parentId": "AU_ffvwM40Hx1Kh6rfQA",
          "name": "derp2child2"
        }
      },
      {
        "_index": "test",
        "_type": "child",
        "_id": "AU_fjD_U40Hx1Kh6rfQF",
        "_score": 1,
        "_source": {
          "parentId": "AU_ffvwM40Hx1Kh6rfQA",
          "name": "derp2child1"
        }
      },
      {
        "_index": "test",
        "_type": "child",
        "_id": "AU_fjKqf40Hx1Kh6rfQH",
        "_score": 1,
        "_source": {
          "parentId": "AU_ffvwM40Hx1Kh6rfQA",
          "name": "derp2child3"
        }
      }
    ]
  },
  "aggregations": {
    "ids": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "au_ffvwm40hx1kh6rfqa",
          "doc_count": 3
        }
      ]
    }
  }
}

По какой-то причине отфильтрованный ключ возвращается в нижнем регистре, поэтому невозможно запросить родительский элемент для ElasticSearch.

GET http://localhost:9200/test/A/au_ffvwm40hx1kh6rfqa

Response:
{
  "_index": "test",
  "_type": "A",
  "_id": "au_ffvwm40hx1kh6rfqa",
  "found": false
}

Есть идеи, почему это происходит?


person RecuencoJones    schedule 18.09.2015    source источник
comment
Ваш parentId должен быть проанализирован с помощью keyword анализатора или должен быть "index": "not_analyzed".   -  person Andrei Stefan    schedule 18.09.2015


Ответы (2)


Разница между попаданиями и результатами агрегирования заключается в том, что агрегаты работают на созданных условиях. Они также вернут условия. Хиты возвращают исходный источник.

Как создаются эти термины? В зависимости от выбранного анализатора, который в вашем случае является анализатором по умолчанию, стандартный анализатор. Одно из действий этого анализатора - это нижний регистр всех символов терминов. Как упоминал Андрей, вы должны настроить поле parentId как not_analyzed.

PUT test
{
  "mappings": {
    "B": {
      "properties": {
        "parentId": {
          "type": "string",
          "index": "not_analyzed"
        }
      }
    }
  }   
}
person Jettro Coenradie    schedule 18.09.2015
comment
Хорошо, я вижу. Попробую обновить сопоставления полей, думаю, этого будет достаточно! Спасибо! - person RecuencoJones; 18.09.2015
comment
У меня такая же проблема с сопоставлением ключевых слов. Есть идеи, почему это происходит? - person g.lahlou; 29.01.2018

Я опаздываю с вечеринки, но у меня была такая же проблема, и я понял, что это вызвано нормализацией.

Вы должны изменить mapping из index, если вы хотите предотвратить любую нормализацию, изменяющую агрегированные значения на нижний регистр.

Вы можете проверить текущее сопоставление в DevTools console, набрав

GET /A/_mapping
GET /B/_mapping

Когда вы видите структуру индекса, вы должны увидеть настройку поля parentId.

Если вы не хотите изменять поведение поля, но также хотите избежать нормализации во время агрегирования, вы можете добавить подполе в поле parentId.

Для изменения сопоставления вам необходимо удалить индекс и воссоздать его с новым сопоставлением:

В вашем случае это выглядит так (содержит только поле parentId)

PUT /B/_mapping
{
  "properties": {
    "parentId": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword"
        }
      }
    }
  }
}

то вы должны использовать подполе в запросе:

POST http://localhost:9200/test/B/_search
{
  "query": {
    "query_string": {
      "default_field": "name",
      "query": "derp2*"
    }
  },
  "aggregations": {
    "ids": {
      "terms": {
        "field": "parentId.keyword",
        "order": {"_key": "desc"}
      }
    }
  }
}
person Zoltán Süle    schedule 06.11.2019
comment
Идея подполя верна. Жаль, что мы не можем сделать его более интуитивно понятным (например, какое-то поле для извлечения исходного значения источника) из-за того, как работает ES. - person Hoàng Long; 04.02.2021