# Синонимы для словосочетаний, сохранение исходных слов

**URL:** <https://discuss.elastic.co/t/topic/62797>\
**Category:** Вопросы на русском языке\
**Created:** [October 12, 2016, 10:43am UTC](https://discuss.elastic.co/t/topic/62797 "2016-10-12T10:43:42Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ilya\_Shipilov](https://avatars.discourse-cdn.com/v4/letter/i/e9a140/32.png) [@Ilya\_Shipilov](https://discuss.elastic.co/u/Ilya_Shipilov)\
**Post date:** [October 12, 2016, 10:43am UTC](https://discuss.elastic.co/t/topic/62797/1 "2016-10-12T10:43:42Z")

</div>

Есть задача сохранять в индексе синонимы для словосочетаний.  
Пример:

```
жидкость омывателя -> омывайка
монопод для селфи, палка для селфи -> селфипалка

```

Настроил анализатор следующим образом:

```
PUT /multiwords_synonyms_index
{
  "settings": {
    "analysis": {
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "монопод для селфи, палка для селфи=>селфипалка"
          ]
        }
      },
      "analyzer": {
        "my_synonyms": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_synonym_filter"
          ]
        }
      }
    }
  }
}

```

Фильтр отрабатывает, заменяя словосочетания на указанный в таблице терм:

```
POST /multiwords_synonyms_index/_analyze?analyzer=my_synonyms
{
  "text": "у меня есть монопод для селфи" 
}

POST /multiwords_synonyms_index/_analyze?analyzer=my_synonyms
{
  "text": "у меня есть селфипалка" 
}

{
   "tokens": [
      {
         "token": "text",
         "start_offset": 5,
         "end_offset": 9,
         "type": "<ALPHANUM>",
         "position": 1
      },
      {
         "token": "у",
         "start_offset": 22,
         "end_offset": 23,
         "type": "<ALPHANUM>",
         "position": 4
      },
      {
         "token": "меня",
         "start_offset": 24,
         "end_offset": 28,
         "type": "<ALPHANUM>",
         "position": 5
      },
      {
         "token": "есть",
         "start_offset": 29,
         "end_offset": 33,
         "type": "<ALPHANUM>",
         "position": 6
      },
      {
         "token": "селфипалка",
         "start_offset": 34,
         "end_offset": 51,
         "type": "SYNONYM",
         "position": 7
      }
   ]

```

Таким образом, я могу найти все нужные документы по запросу "селфипалка", но по запросу "монопод для селфи" документ найден не будет.

Использую такой запрос:

```
GET /multiwords_synonyms_index/data/_search
{
   "from": 0,
   "size": 10,
   "query": {
      "filtered": {
         "query": {
            "function_score": {
               "query": {
                  "simple_query_string": {
                     "query": "монопод для селфи",
                     "fields": [
                        "name"
                     ],
                     "default_operator": "or",
                     "analyzer": "my_synonyms",
                     "minimum_should_match": "1"
                  }
               }
            }
         }
      }
   }
}

```

Как можно решить эту задачу? Может быть, есть возможность сохранять исходные термы, или обязательно использовать match\_phrase?

---

<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:** [October 12, 2016, 10:43pm UTC](https://discuss.elastic.co/t/topic/62797/2 "2016-10-12T22:43:13Z")

</div>

За редким исключением, данные должны быть индексированы с тем же самым анализатором, который вы используете при поиске. См. [https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping-intro.html#\_analyzer](https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping-intro.html#_analyzer)

---

<div class="post-metadata">

**Author:** ![Ilya\_Shipilov](https://avatars.discourse-cdn.com/v4/letter/i/e9a140/32.png) [@Ilya\_Shipilov](https://discuss.elastic.co/u/Ilya_Shipilov)\
**Post date:** [January 31, 2017, 6:15pm UTC](https://discuss.elastic.co/t/topic/62797/3 "2017-01-31T18:15:29Z")

</div>

Игорь, так я и не разобрался с этой проблемой.

Насколько понимаю, мой индекс настроен так что и индексация и поиск происходят с синонимами.  
Но в результате все равно после использования simple contraction (`=>`) я теряю возможность найти документ по оригинальным словам (как в примере выше).

В сети пишут про некий параметр `expand` для фильтра синонимов который вроде бы должен влиять на сохранение исходных термов - попробовал задавать, но его влияние на вектора термов не обнаружил..

---

<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:** [January 31, 2017, 6:46pm UTC](https://discuss.elastic.co/t/topic/62797/4 "2017-01-31T18:46:21Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![Ilya\_Shipilov](https://avatars.discourse-cdn.com/v4/letter/i/e9a140/32.png) [@Ilya\_Shipilov](https://discuss.elastic.co/u/Ilya_Shipilov)\
**Post date:** [January 31, 2017, 7:22pm UTC](https://discuss.elastic.co/t/topic/62797/5 "2017-01-31T19:22:09Z")

</div>

Да, конечно.

Настройки:

```
PUT /multiwords_synonyms_index
{
  "settings": {
    "analysis": {
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "монопод для селфи, палка для селфи=>селфипалка"
          ]
        }
      },
      "analyzer": {
        "my_synonyms": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_synonym_filter"
          ]
        }
      }
    }
  }
}

```

Маппинг:

```
PUT /multiwords_synonyms_index/_mapping/goods
{
   "properties": {
      "good_name": {
         "type": "string",
         "store": true,
         "index": "analyzed",
         "search_analyzer": "my_synonyms",
         "index_analyzer": "my_synonyms",
         "term_vector": "with_positions_offsets_payloads"
      }
   }
}

```

Тестовые данные (документы 1,2,3):

```
PUT /multiwords_synonyms_index/goods/1
{
    "good_name" : "монопод для селфи"
}

PUT /multiwords_synonyms_index/goods/2
{
    "good_name" : "палка для селфи"
}

PUT /multiwords_synonyms_index/goods/3
{
    "good_name" : "селфипалка"
}

```

Запрос:

```
GET /multiwords_synonyms_index/goods/_search
{
   "query": {
      "filtered": {
         "query": {
            "function_score": {
               "query": {
                  "simple_query_string": {
                     "query": "палка для селфи",
                     "fields": [
                        "good_name"
                     ],
                     "default_operator": "and",
                     "minimum_should_match": "1"
                  }
               }
            }
         }
      }
   }
}

```

Результат запроса:

```
{
   "took": 3,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 0,
      "max_score": null,
      "hits": []
   }
}

```

Идентичный результат для запроса "монопод для селфи".

А вот для запроса "селфипалка" в результате все три документа:

```
{
   "took": 7,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 3,
      "max_score": 0.30685282,
      "hits": [
         {
            "_index": "multiwords_synonyms_index",
            "_type": "goods",
            "_id": "1",
            "_score": 0.30685282,
            "_source": {
               "good_name": "монопод для селфи"
            }
         },
         {
            "_index": "multiwords_synonyms_index",
            "_type": "goods",
            "_id": "2",
            "_score": 0.30685282,
            "_source": {
               "good_name": "палка для селфи"
            }
         },
         {
            "_index": "multiwords_synonyms_index",
            "_type": "goods",
            "_id": "3",
            "_score": 0.30685282,
            "_source": {
               "good_name": "селфипалка"
            }
         }
      ]
   }
}

```

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

---

<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:** [January 31, 2017, 7:35pm UTC](https://discuss.elastic.co/t/topic/62797/6 "2017-01-31T19:35:18Z")

</div>

А версия Elasticsearch какая?

---

<div class="post-metadata">

**Author:** ![Ilya\_Shipilov](https://avatars.discourse-cdn.com/v4/letter/i/e9a140/32.png) [@Ilya\_Shipilov](https://discuss.elastic.co/u/Ilya_Shipilov)\
**Post date:** [January 31, 2017, 7:50pm UTC](https://discuss.elastic.co/t/topic/62797/7 "2017-01-31T19:50:54Z")

</div>

Elasticsearch 1.5.1

---

<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:** [January 31, 2017, 8:38pm UTC](https://discuss.elastic.co/t/topic/62797/8 "2017-01-31T20:38:30Z")

</div>

Проблема в том, как `simple_query_string` обрабатывает запросы. Дело в том, что при парсинге запрос сначала разбивается по пробелам, и только потом пропускается через анализ. То есть получается что мы анализируем по отдельности токены `палка`, `для`, и `селфи`, и эти токены по отдельности никаким синонимам не соответсвует. Проблема эта давняя и была разрешена только в [5.1.1](https://github.com/elastic/elasticsearch/issues/20841). В 1.5.1 можно перейти на multi\_match, который обрабатывает такие запросы правильно, отказаться от многословных синонимов, или отказаться от simple contraction и индексировать все синонимы, а при поиске синонимы не использовать.

---

<div class="post-metadata">

**Author:** ![Ilya\_Shipilov](https://avatars.discourse-cdn.com/v4/letter/i/e9a140/32.png) [@Ilya\_Shipilov](https://discuss.elastic.co/u/Ilya_Shipilov)\
**Post date:** [February 7, 2017, 4:11pm UTC](https://discuss.elastic.co/t/topic/62797/9 "2017-02-07T16:11:53Z")

</div>

Спасибо за разъяснения, Игорь.

В итоге выбрал вариант с simple contraction + дублирующие поля без фильтра синонимов, и поиск идет по обоим полям.

---

<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:44pm UTC](https://discuss.elastic.co/t/topic/62797/10 "2017-07-06T13:44:01Z")

</div>


