Иерархическое применение синонимов

Добрый день.

Немного запутался с концепцией multiword synonyms. Объясню на примерах.
Индекс и документы:

PUT test_index1
{
  "mappings": {
    "doc": {
      "properties": {
        "full_text": {
          "type": "text",
          "term_vector": "with_positions_offsets",
          "search_analyzer": "main_analyzer",
          "analyzer": "index_analyzer"
        }
      }
    }
  },
  "settings": {
    "index": {
      "analysis": {
        "filter": {
          "synonyms": {
            "type": "synonym_graph",
            "synonyms": [
              "выписка из егрюл, выписка егрюл",
              "единый государственный реестр юридический лицо, егрюл"
            ],
            "expand": true
          }
        },
        "analyzer": {
          "index_analyzer": {
            "filter": [
              "lowercase"
            ],
            "type": "custom",
            "tokenizer": "standard"
          },
          "main_analyzer": {
            "filter": [
              "lowercase",
              "synonyms"
            ],
            "char_filter": [
              "delimiter_char_filter"
            ],
            "type": "custom",
            "tokenizer": "standard"
          }
        },
        "char_filter": {
          "delimiter_char_filter": {
            "type": "mapping",
            "mappings": [
              "/=>_",
              "-=>_"
            ]
          }
        }
      }
    }
  }
}

PUT test_index1/doc/1
{
  "full_text": "об особенность оформление выписка из егрюл"
}

PUT test_index1/doc/2
{
  "full_text": "выписка единый государственный реестр юридический лицо"
}

PUT test_index1/doc/3
{
  "full_text": "единый государственный реестр юридический лицо"
}

Поиск:

POST test_index1/_search?search_type=dfs_query_then_fetch
{
  "query": {
    "match": {
      "full_text": {
        "query": "выписка егрюл",
        "operator": "or"
      }
    }
  },
  "highlight": {
    "fields": {
      "full_text": {}
    }
  }
}

Я ожидаю, что при поиске у меня найдутся все документы, так как синоним "егрюл" должен поменяться на "единый государственный реестр юридический лицо", но магии не происходит и находится только первый документ. Есть какие-то способы побороть проблему средствами эластика? Или нам делать предобработку синонимов в коде?

Спасибо за хорошие пример. Давайте разбираться. Посмотрим что у нас происходит с запросом:

POST test_index1/_validate/query?explain
{
  "query": {
    "match": {
      "full_text": {
        "query": "выписка егрюл",
        "operator": "or"
      }
    }
  }
}

получаем:

{
...
      "explanation" : """(full_text:"выписка из егрюл" full_text:"выписка егрюл")"""
...
}

Почему это происходит? Потому что мы применили первую строку из синонимов:
"выписка из егрюл, выписка егрюл", синонимы рекурсивно не применяются и мы ищем каждый найденный синоним как строку.

Игорь, спасибо, это как раз мне понятно. Нет ли такого подхода, чтобы синонимы, состоящие из нескольких слов, применялись рекурсивно?

До этого мы применяли подход с simple contraction при индексации, но такой подход при индексации заменяет многословные синонимы на 1 слово, что тоже накладывает свои ограничения при поиске. Сейчас кажется, что synonym_graph + search_analyzer - самое оптимальное решение, но могу ошибаться.

Ещё я пробовал подход, когда мы добавляем 2 фильтра синонимов, первый - с "выписка из егрюл, выписка егрюл", второй с "единый государственный реестр юридический лицо, егрюл", тогда в pipeline обработки вроде всё заменяется как надо, но это опять же накладывает на нас обязанность разделять синонимы на 2 группы.

Если нет возможности рекурсивной подстановки синонимов через elasticsearch/lucene, будем делать предобработку рекурсивную наших синонимов на 1-2 уровня вложенности. Спасибо ещё раз.

Я не очень понимаю, что вы хотите добиться. Если честно, я не понимаю причин по которым вы добавили первую строку синонимов.

Есть исторически накопленная база синонимов, которые раньше применялись в поиске на другом движке. Предположим, что первая строчка синонимов это "выписка егрюл, оформить выписка егрюл, запросить егрюл, запросить выписка егрюл", не просто добавляем "из", а чуть сложнее строка. При этом, например, синонимы уровня "выписка, запросить, запросить выписка, оформить" нас могут не устраивать по каким-то причинам, связанным с конкретным набором наших документов и применяться могут в контексте только с "егрюл" (или каким-то другим словом, которое само по себе является аббревиатурой, которая добавлена так же в синонимы).

Это подробное описание того, как ваша система не работает в данный момент и историческая справка. Я теперь понимаю, почему вы добавили первую строку - потому что так было в прошлой системе. Но я, все еще, не очень понимаю, что вы хотите добиться.

Название документа: "выписка единый государственный реестр юридический лицо".

Пользователь ищет: "выписка егрюл" или "запросить егрюл".
При этом данный документ не находится, так как вы уже говорили, срабатывает синоним на "выписка егрюл", но подстановки "егрюл, единый государственный реестр юридический лицо" не происходит.

А хотелось бы, чтобы он находился.

Эту часть я понимаю, но ее очень просто достичь убрав первую строку из списка синонимов из вашего примера. Мне хотелось бы понять, почему вам такой подход не подходит.

Если убрать эту строчку, то вот такой вариант запроса вернёт пустой результат:

POST test_index1/_search?search_type=dfs_query_then_fetch    
    {
      "query": {
        "match": {
          "full_text": {
            "query": "запросить егрюл",
            "minimum_should_match": "3<75%"
          }
        }
      },
      "highlight": {
        "fields": {
          "full_text": {}
        }
      }
    }

При замене or на and или добавлении minimum_should_match больше 1 получаем 0 результатов. Реальный запрос в разы сложнее, там и minimum_should_match, и match_phrase и так далее.

В любом случае, как я понял, нам нужно именно перерабатывать словарь синонимов, а не искать решение с помощью elasticsearch, верно?

Если вы хотите искать решение с помощью elasticsearch, то нужно более точно определить проблему для которой мы ищем это решение. Например, если у вас в запросе только 2 слова, то minimum_should_match больше 2-х не имеет никакого смысла. То есть, хотелось бы понять, откуда 3 там взялось и хорошее ли значение это для elasticsearch.

Если вы хотите засунуть elasticsearch в прокрустово ложе старой системы, то надо лучше разобраться, как старая система работает, или хотя бы понять, что вы заменяете. По той информации, которая пока появилась, мне кажется, что фильтр synonym вместо synonym_graph будет вести себя более похоже на поведение вашей старой системы.