我正在使用德语分析器来标记某些内容。我知道它基本上是“小写”,“german_stop”,“german_keywords”,“german_normalization”,“german_stemmer”的宏过滤器。
我的问题与正常化过滤器有关。以下是过滤器的Elasticsearch Documentation和Lucene Implementation。问题在于,将ae和oe视为德语字母ä,ö和ü,因此转换为a,o,u。
第二次改造是好的,但第一次转变导致的问题多于解决的问题。在德语文本中通常没有ae,ue,oe真正代表ä,ü,ö。他们实际出现的大部分时间都是外来词,来自拉丁语或英语,如'Aearodynamik'(空气动力学)。过滤器然后将'Ae'解释为'Ä',然后将其转换为'A'。这产生'arodynamik'作为标记。通常这不是问题,因为搜索字也用该过滤器标准化。但是,如果与通配符搜索结合使用,则会出现问题:
想象一下像'FooEdit'这样的词,这将被标记为'foodit'。搜索“编辑OR *编辑*”(这是用户搜索“编辑”时的常规搜索)不会产生结果,因为“编辑”的“e”丢失了。由于我的内容有很多这样的单词,而且人们正在搜索部分单词,所以它并不像看起来那么多边缘情况。
所以我的问题是有没有办法摆脱'ae - > '转型?我的理解是,这是German2 snowball algorithm的一部分,所以可能无法改变。这是否意味着我必须摆脱整个规范化步骤,或者我可以提供我自己的雪球算法版本,我只是去除了我不喜欢的部分(没有找到关于如何使用自定义的任何文档用于规范化的雪球算法?
干杯
汤姆
答案 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
应该可以解决问题。