# Genre Expansion в Elasticsearch 6.1

**URL:** <https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708>\
**Category:** Вопросы на русском языке\
**Created:** [January 16, 2018, 12:27pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708 "2018-01-16T12:27:35Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 16, 2018, 12:27pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/1 "2018-01-16T12:27:35Z")

</div>

Здравствуйте!

Во втором эластике была возможность создавать иерархические структуры синонимов для поиска:  
[https://www.elastic.co/guide/en/elasticsearch/guide/current/synonyms-expand-or-contract.html](https://www.elastic.co/guide/en/elasticsearch/guide/current/synonyms-expand-or-contract.html)

Однако в шестой версии я такой опции не вижу. Обычный поиск по синонимам работает. Есть ли возможность задать какую-то онтологию, и, скажем, при поиске pet находить документы и с cat, и с dog?

---

<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 16, 2018, 1:45pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/2 "2018-01-16T13:45:21Z")

</div>

> [@acorned](#):
>
> Однако в шестой версии я такой опции не вижу.

Формат синонимов не менялся очень давно. Вы не могли бы показать полный пример, который работал в 2.x и не работает в 6.x?

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 16, 2018, 3:30pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/3 "2018-01-16T15:30:27Z")

</div>

Вот так объявляю аналайзер (вместе с маппингом):

curl -XPUT 'localhost:9200/pet\_index?pretty' -H 'Content-Type: application/json' -d'  
{ "mappings": {  
"pet\_owner": {  
"properties": {  
"name": { "type": "text" },  
"age": { "type": "integer" },  
"pet": { "type": "text" },  
"created": {  
"type": "date",  
"format": "strict\_date\_optional\_time||epoch\_millis"  
}  
}  
}  
},  
"settings": {  
"index" : {  
"analysis" : {  
"analyzer" : {  
"search\_synonyms" : {  
"tokenizer" : "whitespace",  
"filter" : ["graph\_synonyms"]  
}  
},  
"filter" : {  
"graph\_synonyms" : {  
"type" : "synonym\_graph",  
"synonyms\_path" : "analysis/synonym2.txt"  
}  
}  
}  
}  
}  
}  
'

Вот так выглядит файл с синонимами:

"cat =\> cat,pet",  
"kitten =\> kitten,cat,pet",  
"dog =\> dog,pet",  
"puppy =\> puppy,dog,pet"

Вот так - запрос:

curl -XGET 'localhost:9200/pet\_index/\_search?pretty' -H 'Content-Type: application/json' -d'  
{  
"query" : {  
"match" : {  
"pet" : {  
"query":"pet",  
"analyzer": "search\_synonyms"  
}  
}  
}  
}  
'

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 16, 2018, 3:43pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/4 "2018-01-16T15:43:14Z")

</div>

Возможно, так будет нагляднее:  
[https://pastebin.com/mMRgVks0](https://pastebin.com/mMRgVks0)

---

<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 16, 2018, 3:59pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/5 "2018-01-16T15:59:26Z")

</div>

В вашем примере синонимы используются при поиске. Поэтому `cat` будет искать `cat` и `pet`, но `pet` будет искать только `pet`. Надо либо переместить синонимы из поиска в индексирование (и изменить тип на просто `synonyms`), либо вывернуть синонимы наизнанку:

```auto
pet => pet, cat, kitten, dog, puppy
cat => kitten, cat
dog => dog, puppy

```

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 17, 2018, 6:37am UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/6 "2018-01-17T06:37:14Z")

</div>

Понял, спасибо. А есть ли возможность использовать при этом вложенную иерархию, то есть указать для pet только его непосредственных потомков - cat и dog, но при этом искать по их синонимам тоже? Иначе, боюсь, мало-мальски сложная иерархия разрастется до непомерных величин, и ее очень сложно будет описывать.

И еще: подскажите, пожалуйста, аналайзер подхватывает файл с синонимами каждый раз при выполнении запроса, или только при первичной индексации? Если второе, то можно ли заставить его принудительно переиндексировать файл?

---

<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 17, 2018, 3:10pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/7 "2018-01-17T15:10:02Z")

</div>

> [@acorned](#):
>
> А есть ли возможность использовать при этом вложенную иерархию, то есть указать для pet только его непосредственных потомков - cat и dog, но при этом искать по их синонимам тоже?

Можно применить тот же самый фильтр синонимов несколько раз. Ничего более разумного в данный момент в голову не приходит.

> [@acorned](#):
>
> И еще: подскажите, пожалуйста, аналайзер подхватывает файл с синонимами каждый раз при выполнении запроса, или только при первичной индексации? Если второе, то можно ли заставить его принудительно переиндексировать файл?

Аналайзер перегружает файл синонимов при [открытии индекса](https://www.elastic.co/guide/en/elasticsearch/reference/6.1/indices-open-close.html). Но при этом записи, которые уже были проиндексированы, не переиндексируются. Их можно переиндексировать с помощью команды [reindex](https://www.elastic.co/guide/en/elasticsearch/reference/6.1/docs-reindex.html).

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 19, 2018, 9:01am UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/8 "2018-01-19T09:01:25Z")

</div>

> Можно применить тот же самый фильтр синонимов несколько раз. Ничего более разумного в данный момент в голову не приходит.

К сожалению, не получается( Вы не могли бы подсказать, что я на этот раз делаю не так?

```
pet => pet, kitty, dog, bird
kitty => kitty, kitten
dog => dog, puppy 
bird => bird, parrot

```

Запрос:

```
curl -XPUT 'localhost:9200/pet_index?pretty' -H 'Content-Type: application/json' -d'
{"mappings": {
    "pet_owner": { 
      "properties": { 
        "name": { "type": "text" }, 
        "age": { "type": "integer" },  
        "pet": { "type": "text" }, 
        "created": {
          "type": "date", 
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    }
  },
    "settings": {
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "synonym_analyzer" : {
                        "tokenizer" : "whitespace",
                        "filter" : ["synonym", "synonym"]
                    }
                },              
                "filter" : {
                    "synonym" : {
                        "type" : "synonym",
                        "synonyms_path" : "analysis/synonym2.txt"
                                }
                           }
            }
        }
    }
}
'

```

И результат:

```
{
  "error" : {
    "root_cause" : [
      {
        "type" : "illegal_argument_exception",
        "reason" : "failed to build synonyms"
      }
    ],
    "type" : "illegal_argument_exception",
    "reason" : "failed to build synonyms",
    "caused_by" : {
      "type" : "parse_exception",
      "reason" : "Invalid synonym rule at line 1",
      "caused_by" : {
        "type" : "illegal_argument_exception",
        "reason" : "term: pet analyzed to a token (kitty) with position increment != 1 (got: 0)"
      }
    }
  },
  "status" : 400
}

```

---

<div class="post-metadata">

**Author:** ![leov](https://avatars.discourse-cdn.com/v4/letter/l/ed655f/32.png) [@leov](https://discuss.elastic.co/u/leov)\
**Post date:** [January 19, 2018, 12:00pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/9 "2018-01-19T12:00:47Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 19, 2018, 12:50pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/10 "2018-01-19T12:50:46Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![leov](https://avatars.discourse-cdn.com/v4/letter/l/ed655f/32.png) [@leov](https://discuss.elastic.co/u/leov)\
**Post date:** [January 19, 2018, 12:57pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/11 "2018-01-19T12:57:29Z")

</div>

попробуйте и эту строчку порезать до самого минимума  
попробуйте воткнуть между двумя вызовами одного фильтра что-то еще  
попробуйте определить фильтр для второго прохода с другим именем  
(вообще имена я бы давал какие-то более свои избегая стандартных эластиковых слов  
черт его знает что он там внутри подумает и как их интерпретирует)

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 19, 2018, 1:17pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/12 "2018-01-19T13:17:48Z")

</div>

Все это уже попробовал, к сожалению, с неизменным результатом.

---

<div class="post-metadata">

**Author:** ![leov](https://avatars.discourse-cdn.com/v4/letter/l/ed655f/32.png) [@leov](https://discuss.elastic.co/u/leov)\
**Post date:** [January 19, 2018, 1:20pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/13 "2018-01-19T13:20:36Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 19, 2018, 1:31pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/14 "2018-01-19T13:31:39Z")

</div>

Нет, дело не в том, что списков два. Дело в том, что, когда он матчится сам на себя, происходит что-то непонятное. Например, если я укажу два фильтра синонимов и обращусь в них к разным файлам с разным содержимым, то все ок. А вот если в этих двух файлах встречается одинаковый термин, то вылетает эта ошибка.

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 19, 2018, 1:38pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/15 "2018-01-19T13:38:49Z")

</div>

Давайте покажу, как сейчас это выглядит:

```
curl -XPUT 'localhost:9200/pet_index?pretty' -H 'Content-Type: application/json' -d'
{"mappings": {
    "pet_owner": { 
      "properties": { 
        "name": { "type": "text" }, 
        "age": { "type": "integer" },  
        "pet": { "type": "text" }, 
        "created": {
          "type": "date", 
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    }
  },
    "settings": {
        "index" : {
            "analysis" : {
                "analyzer" : {
                    "synonym_analyzer" : {
                        "tokenizer" : "whitespace",
                        "filter" : ["synonym_filter", "do_nothing", "another_synonym_filter"]
                    }
                },              
                "filter" : {
                    "synonym_filter" : {
                        "type" : "synonym_graph",
                        "synonyms_path" : "analysis/synonym2.txt"
                    },
                    "another_synonym_filter" : {
                        "type" : "synonym_graph",
                        "synonyms_path" : "analysis/synonym3.txt"
                    },
                    "do_nothing" : {
                        "type" : "standard"
                    }
                }
            }
        }
    }
}
'

```

Файлы синонимов:

```
pet => pet, kitty, dog, bird
kitty => kitty, kitten
dog => dog, puppy 
bird => bird, parrot

```

и

`pet, kitty, dog, bird`

Ошибка та же самая:

```
"type" : "illegal_argument_exception",
        "reason" : "term: pet analyzed to a token (kitty) with position increment != 1 (got: 0)"
```

---

<div class="post-metadata">

**Author:** ![leov](https://avatars.discourse-cdn.com/v4/letter/l/ed655f/32.png) [@leov](https://discuss.elastic.co/u/leov)\
**Post date:** [January 19, 2018, 1:53pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/16 "2018-01-19T13:53:18Z")

</div>

а в чем собственно смысл двойного прогона одного и того-же правила?  
и почему вы пишете dog =\> dog слева и справа одно и то-же?  
по моему дак слева должно быть слово а справа синонимы  
по моему тут вообще можно чарфильтр типа мапинг сделать чтобы заменяло одно на другое и все  
а так как вы делаете то надо каждый уровень вашей иерархии поместить в отдельное описание синонимов и потом прогнать по очереди  
вот так как-то я это понимаю

---

<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 19, 2018, 1:59pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/17 "2018-01-19T13:59:00Z")

</div>

Да, я про positions increment не подумал. Вы хотите эти синонимы применять при индексировании или при поиске?

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 19, 2018, 2:01pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/18 "2018-01-19T14:01:20Z")

</div>

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

---

<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 19, 2018, 2:05pm UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/19 "2018-01-19T14:05:34Z")

</div>

Да, наверное, проще всего тогда написать скрипт, который будет вам генерировать расширенный список синонимов из списка, который вы создадите и будете поддерживать.

---

<div class="post-metadata">

**Author:** ![acorned](https://avatars.discourse-cdn.com/v4/letter/a/ccd318/32.png) [@acorned](https://discuss.elastic.co/u/acorned)\
**Post date:** [January 22, 2018, 8:59am UTC](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708/20 "2018-01-22T08:59:15Z")

</div>

Пока у меня нет необходимых словарей, я сгенерировал образец синонимов, которые буду индексировать - 10 строчек, в которых 70 тысяч терминов матчатся на один:

```
 synonym1_1, synonym1_2, ... synonym1_70000 => term1
 synonym2_1, synonym2_2, ... synonym2_70000 => term2
...
 synonym10_1, synonym10_2, ... synonym10_70000 => term10

```

Пытаюсь сгенерировать индекс с этим фильтром, но эластик не реагирует вот уже 20 минут. Как вы считаете, это надолго? (на тестовой системе 4 ядра по 2,6 Гб, 16 гб оперативки и ssd) Можно ли запустить эластик с конкретными параметрами по производительности, чтобы он не стеснялся использовать ресурсы?

[Next page](https://discuss.elastic.co/t/genre-expansion-elasticsearch-6-1/115708.md?page=2)
