ElasticSearch возвращает только документы с отличным значением

Скажем, у меня есть данные данные

{
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "GEORGE",
            "favorite_cars" : [ "honda","Hyundae" ]
          }

Всякий раз, когда я запрашиваю эти данные при поиске людей, чья любимая машина - Toyota, они возвращают эти данные.

{

            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }, {
            "name" : "ABC",
            "favorite_cars" : [ "ferrari","toyota" ]
          }

результатом являются Две записи с именем ABC. Как выбрать только отдельные документы? Результат, который я хочу получить, это только это

{
                "name" : "ABC",
                "favorite_cars" : [ "ferrari","toyota" ]
              }

Вот мой запрос

{
    "fuzzy_like_this_field" : {
        "favorite_cars" : {
            "like_text" : "toyota",
            "max_query_terms" : 12
        }
    }
}

Я использую ElasticSearch 1.0.0. с клиентом java API


person user962206    schedule 01.07.2014    source источник
comment
Почему бы не вернуть ДЖОРДЖА? Каков ваш запрос? Этот вопрос требует более подробной информации, чтобы быть полезным (и на него можно ответить)   -  person Burkhard    schedule 01.07.2014
comment
@Burkhard Я обновил свой вопрос. Измените благосклонность Джорджа на Хёндэ   -  person user962206    schedule 01.07.2014


Ответы (4)


Вы можете устранить дубликаты, используя агрегации. С агрегацией терминов результаты будут сгруппированы по одному полю, например. name, а также обеспечивает количество вхождений каждого значения поля и сортирует результаты по этому количеству (по убыванию).

{
  "query": {
    "fuzzy_like_this_field": {
      "favorite_cars": {
        "like_text": "toyota",
        "max_query_terms": 12
      }
    }
  },
  "aggs": {
    "grouped_by_name": {
      "terms": {
        "field": "name",
        "size": 0
      }
    }
  }
}

В дополнение к hits результат также будет содержать buckets с уникальными значениями в key и с количеством в doc_count:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.19178301,
    "hits" : [ {
      "_index" : "pru",
      "_type" : "pru",
      "_id" : "vGkoVV5cR8SN3lvbWzLaFQ",
      "_score" : 0.19178301,
      "_source":{"name":"ABC","favorite_cars":["ferrari","toyota"]}
    }, {
      "_index" : "pru",
      "_type" : "pru",
      "_id" : "IdEbAcI6TM6oCVxCI_3fug",
      "_score" : 0.19178301,
      "_source":{"name":"ABC","favorite_cars":["ferrari","toyota"]}
    } ]
  },
  "aggregations" : {
    "grouped_by_name" : {
      "buckets" : [ {
        "key" : "abc",
        "doc_count" : 2
      } ]
    }
  }
}

Обратите внимание, что использование агрегаций будет дорогостоящим из-за устранения дубликатов и сортировки результатов.

person JRL    schedule 13.07.2014
comment
Как мне получить этот уникальный элемент через ведра? он содержит только ключ - person user962206; 28.07.2014
comment
PS: fuzzy_like_this_field устарело в ES 1.6 elastic.co/guide/en/elasticsearch/reference/current/ - person HIRA THAKUR; 08.07.2015
comment
Есть ли способ настроить таргетинг на сами значения массива, а не только на «термины» внутри массивов. Для массивов, содержащих такие значения, как ['mercedes slk', 'bmw 320'], я получаю ['mercedes', 'slk', 'bmw', '320'] в качестве агрегированных ключей. - person mimimimichael; 16.01.2016
comment
См. этот ответ, чтобы узнать, как использовать top_hits для получения первого результата - stackoverflow.com/questions/34878356/ - person Nigel Sheridan-Smith; 18.08.2016

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

В идеале вы должны проиндексировать один и тот же документ с одним и тем же типом и id, так как эти две вещи используются ElasticSearch для предоставления уникального идентификатора _uid для документ. Уникальный идентификатор важен не только из-за его способа обнаружения дубликатов документов, но и из-за обновления одного и того же документа в случае каких-либо изменений вместо вставки нового. Для получения дополнительной информации об индексации документов вы можете прочитать это.

Но для вашей проблемы определенно есть решение. Поскольку вы используете клиент java API, вы можете самостоятельно удалить дубликаты документов на основе значения поля. Фактически, это дает вам больше гибкости для выполнения пользовательских операций с ответами, которые вы получаете от ES.

SearchResponse response = client.prepareSearch().execute().actionGet();
SearchHits hits = response.getHits();

Iterator<SearchHit> iterator = hits.iterator();
Map<String, SearchHit> distinctObjects = new HashMap<String,SearchHit>();
while (iterator.hasNext()) {
    SearchHit searchHit = (SearchHit) iterator.next();
    Map<String, Object> source = searchHit.getSource();
    if(source.get("name") != null){
        distinctObjects.put(source.get("name").toString(),source);
    }

} 

Итак, у вас будет карта уникальных объектов searchHit на вашей карте.

Вы также можете создать сопоставление объектов и использовать его вместо SearchHit.

Надеюсь, это решит вашу проблему. Пожалуйста, простите меня, если есть ошибки в коде. Это всего лишь псевдо-код, чтобы вы поняли, как вы можете решить свою проблему.

Спасибо

person dark_shadow    schedule 13.07.2014
comment
Такой подход затрудняет работу с пейджингом. Поскольку некоторые элементы могут быть удалены на каждой странице, количество результатов на каждой странице может быть отключено. - person evanwong; 16.07.2014
comment
Я голосую за, потому что ответ помогает спрашивающему (и чтобы получить два голоса и разблокировать награду). - person A-312; 16.07.2014

@JRL почти правильно. Вам понадобится агрегация в вашем запросе. Это даст вам список из 10000 лучших «фаворитных_автомобилей» в вашем объекте, упорядоченный по времени появления.

{
    "query":{ "match_all":{ } },
    "size":0,
    "Distinct" : {
        "Cars" : {
            "terms" : { "field" : "favorite_cars", "order": { "_count": "desc"}, "size":10000 }
         }
    }
}

Также стоит отметить, что вы хотите, чтобы ваше поле «favorite_car» не анализировалось, чтобы получить «McLaren F1» вместо «McLaren», «F1».

"favorite_car": {
    "type": "string",
    "index": "not_analyzed"
}
person Eulalie367    schedule 08.04.2015

Для одного сегмента это может быть обработано с помощью специального фильтра, который также заботится о нумерации страниц. Чтобы справиться с вышеуказанным вариантом использования, мы можем использовать поддержку скрипта следующим образом:

  • Определите пользовательский фильтр сценариев. Для этого обсуждения предположим, что он называется AcceptDistinctDocumentScriptFilter.
  • Этот настраиваемый фильтр принимает в качестве входных данных список первичных ключей.
  • Эти первичные ключи являются полями, значения которых будут использоваться для определения уникальности записей.
  • Теперь вместо использования агрегации мы используем обычный поисковый запрос и передаем в запрос пользовательский фильтр скрипта.
  • Если для поиска уже определены критерии фильтра\запроса, добавьте настраиваемый фильтр с помощью логического оператора И.
  • Ниже приведен пример использования псевдосинтаксиса, если запрос: выберите * из myindex, где file_hash = 'hash_value', затем добавьте пользовательский фильтр как:
    выберите * из myindex, где file_hash = 'hash_value' AND AcceptDistinctDocumentScriptFilter(params= ['file_name' , 'Папка'])

Для распределенного поиска это сложно и требует плагина для подключения к фазе QUERY. Подробнее здесь.

person Ajey Dudhe    schedule 30.01.2015
comment
Хотя приятно, что вы предоставили ответ, лучше вставить информацию здесь, а затем указать источник. (ссылки могут стать недоступными со временем) - person George Netu; 30.01.2015
comment
Добавлено краткое описание решения с использованием пользовательского фильтра скриптов. - person Ajey Dudhe; 03.02.2015