Elasticsearch如何配置语言分析器(德语)或构建自定义规范化程序

时间:2016-07-07 15:18:17

标签: elasticsearch lucene snowball

我正在使用德语分析器来标记某些内容。我知道它基本上是“小写”,“german_stop”,“german_keywords”,“german_normalization”,“german_stemmer”的宏过滤器。

我的问题与正常化过滤器有关。以下是过滤器的Elasticsearch DocumentationLucene Implementation。问题在于,将ae和oe视为德语字母ä,ö和ü,因此转换为a,o,u。

第二次改造是好的,但第一次转变导致的问题多于解决的问题。在德语文本中通常没有ae,ue,oe真正代表ä,ü,ö。他们实际出现的大部分时间都是外来词,来自拉丁语或英语,如'Aearodynamik'(空气动力学)。过滤器然后将'Ae'解释为'Ä',然后将其转换为'A'。这产生'arodynamik'作为标记。通常这不是问题,因为搜索字也用该过滤器标准化。但是,如果与通配符搜索结合使用,则会出现问题:

想象一下像'FooEdit'这样的词,这将被标记为'foodit'。搜索“编辑OR *编辑*”(这是用户搜索“编辑”时的常规搜索)不会产生结果,因为“编辑”的“e”丢失了。由于我的内容有很多这样的单词,而且人们正在搜索部分单词,所以它并不像看起来那么多边缘情况。

所以我的问题是有没有办法摆脱'ae - > '转型?我的理解是,这是German2 snowball algorithm的一部分,所以可能无法改变。这是否意味着我必须摆脱整个规范化步骤,或者我可以提供我自己的雪球算法版本,我只是去除了我不喜欢的部分(没有找到关于如何使用自定义的任何文档用于规范化的雪球算法?

干杯

汤姆

2 个答案:

答案 0 :(得分:0)

正如您所说,德国分析仪是一个结合您列出的步骤的管道。 (Documentation

理论上,您可以像上面一样指定自己的分析器,并用另一个替换german_normalization过滤器。例如Pattern Replace Token Filter。我从未使用它,但我猜测语法等于Char替换令牌过滤器(link)。

答案 1 :(得分:0)

此转换由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应该可以解决问题。