2

在 lunr 中为希腊词注册新的词干分析器功能无法按预期工作。是我在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!'
  })
4

1 回答 1

3

在 lunr 中,词干分析器被实现为管道功能。对文档进行索引时对文档中的每个单词执行管道函数,在搜索时对搜索查询中的每个单词执行管道函数。

对于在管道中工作的函数,它必须实现一个非常简单的接口。它需要接受单个字符串作为输入,并且必须以字符串作为输出进行响应。

因此,一个非常简单(且无用)的管道函数如下所示:

var simplePipelineFunction = function (word) {
  return word
}

要真正使用这个管道功能,我们需要做两件事:

  1. 将其注册为管道函数,这允许 lunr 正确序列化和反序列化您的管道。
  2. 将其添加到您的索引管道。

看起来像这样:

// 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 的默认语言是英语,因此默认情况下,它包括专门用于英语的管道函数。英语和希腊语有很大的不同,您可能会在尝试使用英语默认值索引希腊语单词时遇到问题,因此我们需要执行以下操作:

  1. 用我们的语言特定词干替换默认词干分析器
  2. 删除对非拉丁字符效果不佳的默认修剪器
  3. 替换/删除默认的停用词过滤器,它不太可能在英语以外的语言上大量使用。

修剪器和停用词过滤器是作为管道函数实现的,因此对于词干分析器来说,实现特定于语言的过滤器是类似的。

因此,要为希腊语设置 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 创建语言扩展的示例。你甚至可以提交一份希腊文!

编辑看起来我并不lunr.Pipeline像我想象的那样了解API,没有replace函数,而是我们只是在要删除的函数之后插入替换,然后将其删除。

编辑添加这个以帮助将来的其他人......事实证明问题出在lunr中令牌的外壳。lunr 想要将所有标记都视为小写,这是在tokenizer中完成的,没有任何可配置性。对于大多数语言处理函数来说,这不是问题,事实上,大多数假设单词是小写的。在这种情况下,由于希腊语词干的复杂性,希腊词干分析器仅对大写单词进行词干提取(我不是希腊语,因此无法评论词干提取的复杂程度)。一种解决方案是在调用希腊词干分析器之前转换为大写,然后在将标记传递到管道的其余部分之前转换回小写。

于 2016-09-07T19:38:21.947 回答