Genre Expansion в Elasticsearch 6.1

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

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

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

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

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

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"
}
}
}
}
'

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

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

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

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

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

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

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

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

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

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
}

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

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

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

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

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

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

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

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)"

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

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

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

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

Пока у меня нет необходимых словарей, я сгенерировал образец синонимов, которые буду индексировать - 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) Можно ли запустить эластик с конкретными параметрами по производительности, чтобы он не стеснялся использовать ресурсы?