Elasticsearch как настроить анализатор языка (немецкий) или создать собственный нормализатор

Я использую анализатор немецкого языка для токенизации некоторого контента. Я знаю, что это в основном фильтр макросов для "нижних регистров", "german_stop", "german_keywords", "german_normalization", "german_stemmer".

Моя проблема связана с фильтром нормализации. Вот Документация Elasticsearch и Реализация Lucene фильтр. Проблема в том, что ae ue и oe трактуются как немецкие буквы ä,ö и ü и поэтому преобразуются в a,o,u.

Второе преобразование хорошо, но первое приводит к большему количеству проблем, чем решает. Обычно в немецких текстах нет ae, ue, oe, которые действительно представляли бы ä, ü, ö. В большинстве случаев они на самом деле появляются внутри иностранных слов, происходящих от латинского или английского, таких как «Aearodynamik» (аэродинамика). Затем фильтр интерпретирует «Ae» как «Ä», а затем преобразует его в «A». Это дает «ародинамику» в качестве токена. Обычно это не проблема, так как искомое слово также нормализуется с помощью этого фильтра. Однако это становится проблемой в сочетании с поиском по подстановочным знакам:

Представьте себе такое слово, как «FooEdit», оно будет преобразовано в «foodit». Поиск «редактировать ИЛИ * редактировать *» (это мой обычный поиск, когда пользователь ищет «редактировать») не даст результата, поскольку «е» в «редактировать» потерялось. Поскольку в моем контенте много таких слов, и люди ищут частичные слова, это не такой крайний случай, как кажется.

Итак, мой вопрос: есть ли способ избавиться от преобразований «ae -> a»? Насколько я понимаю, это часть алгоритма снежного кома German2, поэтому, вероятно, это не так. быть изменен. Означает ли это, что мне придется избавиться от всего шага нормализации или я могу предоставить свою собственную версию алгоритма снежного кома, в которой я просто удаляю части, которые мне не нравятся (не нашел никакой документации о том, как использовать пользовательский алгоритм снежного кома для нормализации)?

Ваше здоровье

Том


person Tom    schedule 07.07.2016    source источник


Ответы (2)


Как вы сказали, немецкий анализатор представляет собой конвейер, объединяющий перечисленные вами шаги. (Документация)

Теоретически вы можете указать свой собственный анализатор, как описано выше, и заменить фильтр german_normalization другим. Например, Фильтр шаблона замены токена . Я никогда не использовал его, но полагаю, что синтаксис аналогичен фильтру маркеров замены символов (ссылка).

person Slomo    schedule 07.07.2016
comment
Я считаю, что проблема заключается в том, что подстановочные знаки, нечеткие и регулярные выражения запросов не анализируются, поэтому aerody* не соответствует arodynamik - person femtoRgon; 07.07.2016

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

public final class CustomGermanNormalizationFilter extends TokenFilter {
  // FSM with 3 states:
  private static final int N = 0; /* ordinary state */
  private static final int V = 1; /* stops 'u' from entering umlaut state */
  private static final int U = 2; /* umlaut state, allows e-deletion */

  private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);

  public CustomGermanNormalizationFilter(TokenStream input) {
    super(input);
  }

  @Override
  public boolean incrementToken() throws IOException {
    if (input.incrementToken()) {
      int state = N;
      char buffer[] = termAtt.buffer();
      int length = termAtt.length();
      for (int i = 0; i < length; i++) {
        final char c = buffer[i];
        switch(c) {
//Removing this case should prevent e-deletion for "ae"
//        case 'a':
          case 'o':
            state = U;
            break;
          case 'u':
            state = (state == N) ? U : V;
            break;
          case 'e':
            if (state == U)
              length = StemmerUtil.delete(buffer, i--, length);
            state = V;
            break;
          case 'i':
          case 'q':
          case 'y':
            state = V;
            break;
          case 'ä':
            buffer[i] = 'a';
            state = V;
            break;
          case 'ö':
            buffer[i] = 'o';
            state = V;
            break;
          case 'ü': 
            buffer[i] = 'u';
            state = V;
            break;
          case 'ß':
            buffer[i++] = 's';
            buffer = termAtt.resizeBuffer(1+length);
            if (i < length)
              System.arraycopy(buffer, i, buffer, i+1, (length-i));
            buffer[i] = 's';
            length++;
            state = N;
            break;
          default:
            state = N;
        }
      }
      termAtt.setLength(length);
      return true;
    } else {
      return false;
    }
  }
}

Использование этого вместо german_normalization должно помочь.

person femtoRgon    schedule 07.07.2016
comment
Вы правы, изменить детали того, как это должно вести себя в коде, не представляет большой проблемы. Однако, даже если бы я внес изменения в сам алгоритм, я не вижу, как я могу использовать его в Elasticsearch (последнее предложение моего первоначального вопроса). - person Tom; 12.07.2016