2016-12-08 1 views
1

Elasticsearch версию: 5.0.2Elasticsearch простого термин запрос дает Strange баллам

Я заселить мой индекс с:

{_id: 1, tags: ['plop', 'plip', 'plup']}, 
{_id: 2, tags: ['plop', 'plup']}, 
{_id: 3, tags: ['plop']}, 
{_id: 4, tags: ['plap', 'plep']}, 
{_id: 5, tags: ['plop', 'plip', 'plup']}, 
{_id: 6, tags: ['plup', 'plip']}, 
{_id: 7, tags: ['plop', 'plip']} 

Тогда, я хотел бы, чтобы извлечь максимум соответствующих строк для тегов plop и plip:

query: { 
    bool: { 
    should: [ 
     {term: {tags: {value:'plop', _name: 'plop'}}}, 
     {term: {tags: {value:'plip', _name: 'plip'}}} 
    ] 
    } 
} 

что эквивалентно (но я использовал прежнюю для отладки):

query: { 
    bool: { 
    should: [ 
     {terms: {tags: ['plop', 'plip']}} 
    ] 
    } 
} 

Тогда, я считаю, очень странные результаты:

[ 
    { id: '2', score: 0.88002616, tags: [ 'plop', 'plup' ] }, 
    { id: '6', score: 0.88002616, tags: [ 'plup', 'plip' ] }, 
    { id: '5', score: 0.5063205, tags: [ 'plop', 'plip', 'plup' ] }, 
    { id: '7', score: 0.3610978, tags: [ 'plop', 'plip' ] }, 
    { id: '1', score: 0.29277915, tags: [ 'plop', 'plip', 'plup' ] }, 
    { id: '3', score: 0.2876821, tags: [ 'plop' ] } 
] 

Вот деталь ответа:

{ 
    "took": 1, 
    "timed_out": false, 
    "_shards": { 
    "total": 5, 
    "successful": 5, 
    "failed": 0 
    }, 
    "hits": { 
    "total": 6, 
    "max_score": 0.88002616, 
    "hits": [ 
     { 
     "_index": "myindex", 
     "_type": "mytype", 
     "_id": "2", 
     "_score": 0.88002616, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plup" 
      ] 
     }, 
     "matched_queries": [ 
      "plop" 
     ] 
     }, 
     { 
     "_index": "myindex", 
     "_type": "mytype", 
     "_id": "6", 
     "_score": 0.88002616, 
     "_source": { 
      "tags": [ 
      "plup", 
      "plip" 
      ] 
     }, 
     "matched_queries": [ 
      "plip" 
     ] 
     }, 
     { 
     "_index": "myindex", 
     "_type": "mytype", 
     "_id": "5", 
     "_score": 0.5063205, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip", 
      "plup" 
      ] 
     }, 
     "matched_queries": [ 
      "plop", 
      "plip" 
     ] 
     }, 
     { 
     "_index": "myindex", 
     "_type": "mytype", 
     "_id": "7", 
     "_score": 0.3610978, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip" 
      ] 
     }, 
     "matched_queries": [ 
      "plop", 
      "plip" 
     ] 
     }, 
     { 
     "_index": "myindex", 
     "_type": "mytype", 
     "_id": "1", 
     "_score": 0.29277915, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip", 
      "plup" 
      ] 
     }, 
     "matched_queries": [ 
      "plop", 
      "plip" 
     ] 
     }, 
     { 
     "_index": "myindex", 
     "_type": "mytype", 
     "_id": "3", 
     "_score": 0.2876821, 
     "_source": { 
      "tags": [ 
      "plop" 
      ] 
     }, 
     "matched_queries": [ 
      "plop" 
     ] 
     } 
    ] 
    } 
} 

Итак, два вопроса:

  1. Почему ряд обработка только одного запроса (id 2 и 6) имеет лучший балл, чем один соответствующий два (id 1, 5 и 7)?
  2. Почему две строки с одинаковыми тегами могут иметь разные баллы? (id 1 и 5)

Я что-то пропустил?

+0

теги not_analyzed? – blackmamba

+0

метки карты как not_analyzed, и он будет работать нормально – blackmamba

+0

Это не работает. Взгляните на мой комментарий к первому ответу для получения дополнительной информации. – Gnucki

ответ

1

Проблема у меня было красиво объяснено в ответе JGR.

Решение, которое я нашел, это использовать dfs_query_then_fetch как search type.

Вот результирующий запрос с клиентом JavaScript:

body: { 
    query: { 
    bool: { 
     should: [ 
     {terms: {tags: ['plop', 'plip']}} 
     ] 
    } 
    }, 
    searchType: 'dfs_query_then_fetch' 
} 

Обратите внимание, что с большим количеством данных в виде индекса, это, конечно, не будет необходимости, потому что баллы будут балансировать естественно между осколками.

1

Хорошо, я выясню вашу настоящую проблему. Elasitcsearch по умолчанию использует 5 блоков для хранения ваших индексных данных, и если у вас малое число, это может иметь значение в случае вычисления значения _score. Некоторая теория о осколках: https://www.elastic.co/guide/en/elasticsearch/reference/current/_basic_concepts.html

Почему это имеет значение? Потому что для лучшей производительности каждый осколок делает вычисления _score на его собственных данных. Но при расчете оценки значения elasticsearch использовать алгоритм/TF IDF, который опирается на общем числе докторов и частоте поиска терминов (IN осколок) (https://www.elastic.co/guide/en/elasticsearch/guide/current/scoring-theory.html)

Чтобы решить эту проблему, вы можете создать индекс с одним осколком, как это:

{ 
"settings": { 
     "number_of_shards" : 1, 
     "number_of_replicas" : 0 
    }, 
    "mappings": { 
    "my_type": { 
     "properties": { 
     "tags": { 
      "type": "keyword" 
     } 
     } 
    } 
    } 
} 

Вы можете проверить свою теорию с помощью объяснения в поисковом запросе:

http://localhost:9200/test1/my_type/_search?explain

Или вы можете прочитать этот пример, если вам нужно больше;) Таковы мои результаты по Вашему запросу [ «плюх», «PLIP»]

{ 
    "took": 5, 
    "timed_out": false, 
    "_shards": { 
    "total": 5, 
    "successful": 5, 
    "failed": 0 
    }, 
    "hits": { 
    "total": 6, 
    "max_score": 0.9808292, 
    "hits": [ 
     { 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "2", 
     "_score": 0.9808292, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plup" 
      ] 
     } 
     }, 
     { 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "6", 
     "_score": 0.9808292, 
     "_source": { 
      "tags": [ 
      "plup", 
      "plip" 
      ] 
     } 
     }, 
     { 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "5", 
     "_score": 0.5753642, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip", 
      "plup" 
      ] 
     } 
     }, 
     { 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "1", 
     "_score": 0.36464313, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip", 
      "plup" 
      ] 
     } 
     }, 
     { 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "7", 
     "_score": 0.36464313, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip" 
      ] 
     } 
     }, 
     { 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "3", 
     "_score": 0.2876821, 
     "_source": { 
      "tags": [ 
      "plop" 
      ] 
     } 
     } 
    ] 
    } 
} 

Почему документ с хлопками, PLIP, plup в качестве третьего ? Проверьте объяснить для этого:

"_shard": "[test][1]", 
     "_node": "LjGrgIa7QgiPlEvMxqKOdA", 
     "_index": "test", 
     "_type": "my_type", 
     "_id": "5", 
     "_score": 0.5753642, 
     "_source": { 
      "tags": [ 
      "plop", 
      "plip", 
      "plup" 
      ] 
     }, 

Это единственный документ в этом разбиении: тест [1] (я проверен в других возвращенных документах) !! Поэтому значение IDF равно «1», что является наивысшим возможным значением. Оценка = TF/IDF (поэтому для более низкого IDF оценка выше). Проверьте, как это 0.5753642 оценка вычисляется для этого документа:

"value": 0.2876821, 
        "description": "weight(tags:plop... 

         "details": [ 
         { 
          "value": 0.2876821, 
          "description": "idf(docFreq=1, docCount=1)", 

сумма с

{ 
        "value": 0.2876821, 
        "description": "weight(tags:plip.. 

          "value": 0.2876821, 
          "description": "idf(docFreq=1, docCount=1)", 
          "details": [] 
         }, 
+0

Не работает. Я думаю, что большинство анализаторов анализируют «plop» и «plip» как «plop» и «plip», поэтому я не настолько удивлен. Более того, я не думаю, что неправильный анализатор объяснит проблему 2. Спасибо за ваш ответ. – Gnucki

+0

@ Gnucki Да, вы правы! Теперь я вставил точно те же самые документы, что и ваши, а также получил эти странные результаты. Я объяснил это и дал вам решение исправить это. – jgr

+0

Спасибо вам большое за расследование! Это именно то, что происходит, вы правы. Однако установить только один осколок немного сложно решить проблему. Я использовал [searchType] (https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-search-type.html#dfs-query-then-fetch) вместо этого – Gnucki

Смежные вопросы