在lunr中为希腊单词注册一个新的stemmer函数没有按预期工作。这是我在codepen上的代码。我没有收到任何错误,功能stemWord()
单独使用时工作良好,但它无法阻止lunr中的单词。下面是代码示例:
function stemWord(w) {
// code that returns the stemmed word
};
// create the new function
greekStemmer = function (token) {
return stemWord(token);
};
// register it with lunr.Pipeline, this allows you to still serialise the index
lunr.Pipeline.registerFunction(greekStemmer, 'greekStemmer')
var index = lunr(function () {
this.field('title', {boost: 10})
this.field('body')
this.ref('id')
this.pipeline.remove(lunr.trimmer) // it doesn't work well with non-latin characters
this.pipeline.add(greekStemmer)
})
index.add({
id: 1,
title: 'ΚΑΠΟΙΟΣ',
body: 'Foo foo foo!'
})
index.add({
id: 2,
title: 'ΚΑΠΟΙΕΣ',
body: 'Bar bar bar!'
})
index.add({
id: 3,
title: 'ΤΙΠΟΤΑ',
body: 'Bar bar bar!'
})
在lunr中,词干是作为管道函数实现的。在索引文档时对文档中的每个单词执行管道函数,在搜索时对搜索查询中的每个单词执行管道函数。
对于一个在管道中工作的函数,它必须实现一个非常简单的接口。它需要接受单个字符串作为输入,并且必须以字符串作为输出进行响应。
所以一个非常简单(而且没用)的管道函数应该是这样的:
var simplePipelineFunction = function (word) {
return word
}
要真正使用这个管道函数,我们需要做两件事:
- 将其注册为管道函数,这允许lunr正确地序列化和反序列化你的管道。
- 将其添加到您的索引管道中。
看起来像这样:
// registering our pipeline function with the name 'simplePipelineFunction'
lunr.Pipeline.registerFunction(simplePipelineFunction, 'simplePipelineFunction')
var idx = lunr(function () {
// adding the pipeline function to our indexes pipeline
// when defining the pipeline
this.pipeline.add(simplePipelineFunction)
})
现在,您可以使用上面的代码,并替换出管道函数的实现。因此,它可以使用您找到的希腊词干来词干,而不是仅仅返回原封不动的单词,可能像这样:
var myGreekStemmer = function (word) {
// I don't know how to use the greek stemmer, but I think
// its safe to assume it won't be that different than this
return greekStem(word)
}
使lunr适应英语以外的语言需要的不仅仅是添加你的词干。lunr的默认语言是英语,因此,默认情况下,它包含专门用于英语的管道函数。英语和希腊语的差异很大,您可能会遇到用英语默认值索引希腊语单词的问题,因此我们需要做以下操作:
- 将默认的词干替换为特定于语言的词干
- 删除默认的修剪器,它不能很好地处理非拉丁字符
- 替换/删除默认的停止词过滤器,它不太可能在英语以外的语言中使用。
修剪器和停止词过滤器是作为管道函数实现的,因此对词干器实现特定于语言的函数是类似的。
那么,要为希腊语设置lunr,你需要这样做:
var idx = lunr(function () {
this.pipeline.after(lunr.stemmer, greekStemmer)
this.pipeline.remove(lunr.stemmer)
this.pipeline.after(lunr.trimmer, greekTrimmer)
this.pipeline.remove(lunr.trimmer)
this.pipeline.after(lunr.stopWordFilter, greekStopWordFilter)
this.pipeline.remove(lunr.stopWordFilter)
// define the index as normal
this.ref('id')
this.field('title')
this.field('body')
})
要获得更多的灵感,你可以看看优秀的lunr-languages项目,它有许多为lunr创建语言扩展的例子。你甚至可以提交一篇希腊文!
EDIT看起来我不知道lunr.Pipeline
API以及我想的,没有replace
函数,而是我们只是在函数后插入替换,然后删除它。
EDIT添加此内容以帮助将来的其他人…事实证明,问题在于lunr中令牌的大小写。Lunr希望将所有标记都视为小写,这是在标记器中完成的,没有任何可配置性。对于大多数语言处理函数来说,这不是问题,实际上,大多数假设单词是小写的。在这种情况下,由于希腊语词干的复杂性,希腊词干只能词干大写单词(我不是希腊语的演讲者,所以不能评论词干有多复杂)。一个解决方案是在调用希腊词干之前转换为大写,然后在将标记传递给管道的其余部分之前转换回小写。