# Примерный поиск и сортировка результатов

**URL:** <https://discuss.elastic.co/t/topic/36413>\
**Category:** Вопросы на русском языке\
**Created:** [December 4, 2015, 7:14pm UTC](https://discuss.elastic.co/t/topic/36413 "2015-12-04T19:14:01Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 4, 2015, 7:14pm UTC](https://discuss.elastic.co/t/topic/36413/1 "2015-12-04T19:14:01Z")

</div>

Всем добрый вечер!  
Есть документы, в которых хранится 2 поля: Имя и фамилия.  
Нужно создать запрос, который выводил бы документы, В имени и/или фамилии содержится запрос.  
Запросы могут выть вида: "Марина карпова", "м карп", "к марина" и т.п. и отсортировать их по релевантности. Как лучше это реализовать?  
Пробовал через fuzzyquery, но результаты не совсем ожидаемы. Хотя, скорее всего, я не верно их настроил. Только начал изучать es, по этому все для меня в новинку. Если можно, подскажите, как лучше это сделать или же дайте ссылки, где можно почитать. Смотрел документацию, но там много всего, а мне нужно как можно скорее.  
Буду благодарен за помощь.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 5, 2015, 12:09am UTC](https://discuss.elastic.co/t/topic/36413/2 "2015-12-05T00:09:15Z")

</div>

Для поиска под подстроке лучше всего воспользоваться [edgeNGram](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenfilter.html) фильтром. Что касается релевантности, то тут много решений - все зависит от того, что вы под это релевантностью понимаете.

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 5, 2015, 11:14am UTC](https://discuss.elastic.co/t/topic/36413/3 "2015-12-05T11:14:11Z")

</div>

Мне нужно поиск как, скажем, в вк. Только пока только по 2-м полям - имя и фамилия. fuzzy для опечаток, но и корректное выставление релевантности в зависимости от совпадения запроса с данными в эс. Можно какой-то пример? Может, Вы есть в вк или skype, для оперативного общения?  
Спасибо.

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 5, 2015, 2:56pm UTC](https://discuss.elastic.co/t/topic/36413/4 "2015-12-05T14:56:30Z")

</div>

К сожалению, у меня не всегда есть возможность оперативно отвечать на вопросы на форуме, а русско-говорящее сообщество elasticsearch еще не достаточно велико для оказания эффективной самоподдержки. Поэтому для оперативного общения вам лучше обратиться [сюда](https://www.elastic.co/subscriptions).

То есть, вам надо организовать поиск по полному совпадению, по совпадению начала слова и по полному совпадению с опечатками. Полные совпадения должны быть более релевантны, чем совпадения по части слова и совпадения с опечатками. Когда вы ищите, то информация о том, какая часть запроса имя, а какая часть запроса относится к фамилии отсутствует, и пользователь может везти одно, два или даже больше слов в запросе. Я правильно Вас понял? И еще вопрос - имена и фамилии написаны исключительно на русском?

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 5, 2015, 8:44pm UTC](https://discuss.elastic.co/t/topic/36413/5 "2015-12-05T20:44:39Z")

</div>

Да, все верно.

> имена и фамилии написаны исключительно на русском?

В идеале, может быть написано на любом языке.  
Сейчас использую следующий запрос:  
$search = array(  
'query' =\> array(  
'multi\_match' =\> array(  
'fields' =\> ['name', 'lName'],  
'query' =\> urldecode($\_GET['q']),  
'fuzziness' =\> 'auto',  
),  
),  
);  
При помощи чего можно реализовать тот поиск, который Вы описали?

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 5, 2015, 8:45pm UTC](https://discuss.elastic.co/t/topic/36413/6 "2015-12-05T20:45:41Z")

</div>

Да, Вы поняли меня совершенно верно. В идеале, данные могут быть написаны на любом языке.  
Сейчас использую запрос:  
$search = array(  
'query' =\> array(  
'multi\_match' =\> array(  
'fields' =\> ['name', 'lName'],  
'query' =\> urldecode($\_GET['q']).'\*',  
'fuzziness' =\> 'auto',  
),  
),  
);

Как можно реализовать поиск в таком варианте, как Вы описали?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 6, 2015, 5:09am UTC](https://discuss.elastic.co/t/topic/36413/7 "2015-12-06T05:09:57Z")

</div>

Ну тогда, как-то так. Вам надо будет поиграться с `boost`-ами поскольку я не знаю, что для вас важнее - полное совпадение по одному слову или не полное по двум и т. д. Но, надеюсь, основная идея из этого примера очевидна - ищем разными способами и потом выбираем вариант (разные `multi_match`), который более всего подошел (`dis_max`)

```auto
curl -XDELETE "localhost:9200/test?pretty"
curl -XPUT "localhost:9200/test?pretty" -d '{
  "settings": {
    "number_of_replicas": 0,
    "number_of_shards": 1,
    "analysis": {
      "analyzer": {
        "ngram_index_analyzer": {
          "tokenizer": "standard",
          "filter": ["lowercase", "ngram"]
        },
        "ngram_search_analyzer": {
          "tokenizer": "standard",
          "filter": ["lowercase"]
        }
      },
      "filter": {
        "ngram": {
          "type": "edgeNGram",
          "min_gram": 1,
          "max_gram": 50
        }
      }
    }
  },
  "mappings" : {
    "person" : {
      "properties" : {
        "first_name" : {
          "type" : "string",
          "fields": {
            "ngram": {
              "type" : "string",
              "analyzer": "ngram_index_analyzer",
              "search_analyzer": "ngram_search_analyzer"
            }
          }
        },
        "last_name" : {
          "type" : "string",
          "fields": {
            "ngram": {
              "type" : "string",
              "analyzer": "ngram_index_analyzer",
              "search_analyzer": "ngram_search_analyzer"
            }
          }
        }
      }
    }
  }
}'
curl -XPUT "localhost:9200/test/person/1?pretty" -d '{
  "first_name": "John",
  "last_name": "Smith"
}'
curl -XPUT "localhost:9200/test/person/2?pretty" -d '{
  "first_name": "Jill",
  "last_name": "Smith"
}'
curl -XPUT "localhost:9200/test/person/3?pretty" -d '{
  "first_name": "Johan",
  "last_name": "Smith"
}'
curl -XPUT "localhost:9200/test/person/4?pretty" -d '{
  "first_name": "John",
  "last_name": "Brown"
}'
curl -XPOST "localhost:9200/test/_refresh?pretty"
curl -XGET "localhost:9200/test/person/_search?pretty" -d '{
  "query": {
    "dis_max": {
      "queries": [
        {
          "multi_match" : {
            "query": "S. John",
            "fields": ["first_name", "last_name"],
            "type": "most_fields",
            "boost": 3.0
          }
        },
        {
          "multi_match": {
            "query": "S. John",
            "fields": ["first_name", "last_name"],
            "type": "most_fields",
            "fuzziness": "auto",
            "boost": 2.0
          }
        },
        {
          "multi_match": {
            "query": "S. John",
            "fields": ["first_name.ngram", "last_name.ngram"],
            "type": "most_fields",
            "boost": 1.0
          }
        }
      ]
    }
  }
}'

```

Удачи!

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 6, 2015, 10:40am UTC](https://discuss.elastic.co/t/topic/36413/8 "2015-12-06T10:40:27Z")

</div>

В целом, понял. Но не могу пока разобратся, в чем дело: передаю В индекс:  
{ "settings": { "number\_of\_replicas": 0, "number\_of\_shards": 1, "analysis": { "analyzer": { "ngram\_index\_analyzer": { "tokenizer": "standart", "filter": ["lowercase", "ngram"] }, "ngram\_search\_analyzer": { "tokenizer": "standart", "filter": ["lowercase"] } }, "filter": { "ngram": { "type": "edgeNGram", "min\_gram": 1, "max\_gram": 50 } } } }, "mappings": { "user": { "properties": { "first\_name": { "type": "string", "fields": { "ngram": { "type": "string", "analyzer": "ngram\_index\_analyzer", "search\_analyzer": "ngram\_search\_analyzer" } } }, "last\_name": { "type": "string", "fields": { "ngram": { "type": "string", "analyzer": "ngram\_index\_analyzer", "search\_analyzer": "ngram\_search\_analyzer" } } } } } } }  
Но получаю ошибку:  
{"error":{"root\_cause":[{"type":"index\_creation\_exception","reason":"failed to create index"}],"type":"illegal\_argument\_exception","reason":"Custom Analyzer [ngram\_search\_analyzer] failed to find tokenizer under name [standart]"},"status":400}

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 6, 2015, 7:46pm UTC](https://discuss.elastic.co/t/topic/36413/9 "2015-12-06T19:46:18Z")

</div>

Большое спасибо, Игорь! Я нашел свою ошибку и все исправил. Не думал просто, что standart пишеться с 'd' на конце 🙂 и чисто автоматом написал. Сорри.

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 9, 2015, 12:34pm UTC](https://discuss.elastic.co/t/topic/36413/10 "2015-12-09T12:34:10Z")

</div>

Добрый день. Возникает еще вопрос: Чем отличаются 1 и 3 запросы в поиске, который Вы предложили, Игорь?  
В том плане, что как работает fields=field.ngram

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 9, 2015, 1:51pm UTC](https://discuss.elastic.co/t/topic/36413/11 "2015-12-09T13:51:22Z")

</div>

Вместо того, чтобы индексировать поле целиком, edgngram отрывает от слова начало и индескирует его по кусочкам. То есть, при индексировании записи со словом `марина`, вместо добавления в индекс только слова `марина`, он добавляет слова `м`, `ма`, `мар`, `мари`, `марин` и `марина` и все эти слова указывают на эту запись. Таким образом вы можете найти эту запись по любому началу.

---

<div class="post-metadata">

**Author:** ![hmx](https://avatars.discourse-cdn.com/v4/letter/h/ebca7d/32.png) [@hmx](https://discuss.elastic.co/u/hmx)\
**Post date:** [December 9, 2015, 6:37pm UTC](https://discuss.elastic.co/t/topic/36413/12 "2015-12-09T18:37:15Z")

</div>

Подскажите еще, пожалуйста, как реализовать более высокий boosting для, скажем, заголовка, чем описания товара?

---

<div class="post-metadata">

**Author:** ![Igor\_Motov](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/igor_motov/32/45193_2.png) [@Igor\_Motov](https://discuss.elastic.co/u/Igor_Motov)\
**Post date:** [December 9, 2015, 6:50pm UTC](https://discuss.elastic.co/t/topic/36413/13 "2015-12-09T18:50:25Z")

</div>

[https://www.elastic.co/guide/en/elasticsearch/guide/current/multi-match-query.html#\_boosting\_individual\_fields](https://www.elastic.co/guide/en/elasticsearch/guide/current/multi-match-query.html#_boosting_individual_fields)

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [July 6, 2017, 1:50pm UTC](https://discuss.elastic.co/t/topic/36413/14 "2017-07-06T13:50:16Z")

</div>


