词干、变体和重音折叠

问题

索引文本通常包含不同于用户搜索的单词。例如,如果用户搜索 render ,我们希望搜索不仅匹配包含 render ,而且 rendersrenderingrendered 等。

相关问题是口音之一。姓名和借词可以在原始文本中包含重音符号,但不能在用户查询中包含,反之亦然。例如,我们希望用户能够搜索 cafe 并查找包含 café .

的默认分析器 whoosh.fields.TEXT 字段不做词干或重音折叠。

词干提取

词干提取是一个启发式的过程,从单词中删除后缀(有时是前缀),以到达(希望大多数时候)基本单词。whoosh包括几个词干算法,如porter和porter2、paice-housk和lovins。

>>> from whoosh.lang.porter import stem
>>> stem("rendering")
'render'

词干筛选将词干函数应用于它索引的术语以及用户查询中的单词。因此,理论上,根词的所有变化(“render”、“renderd”、“renders”、“rendering”等)都会减少到索引中的单个词,从而节省空间。而且用户在查询中可能使用的所有可能的变体都被减少到根目录,因此词干增强了“召回”。

这个 whoosh.analysis.StemFilter 允许将词干筛选添加到分析器链。

>>> rext = RegexTokenizer()
>>> stream = rext(u"fundamentally willows")
>>> stemmer = StemFilter()
>>> [token.text for token in stemmer(stream)]
[u"fundament", u"willow"]

这个 whoosh.analysis.StemmingAnalyzer() 是一个预包装的分析仪,它结合了标记器、小写过滤器、可选停止过滤器和杆式过滤器:

from whoosh import fields
from whoosh.analysis import StemmingAnalyzer

stem_ana = StemmingAnalyzer()
schema = fields.Schema(title=TEXT(analyzer=stem_ana, stored=True),
                       content=TEXT(analyzer=stem_ana))

词干提取有利弊。

  • 它允许用户查找文档而不必担心单词形式。

  • 它减少了索引的大小,因为它通过将多个单词形式“折叠”为一个基本单词来减少索引的单独单词的数量。

  • 它比使用变体更快(见下文)

  • 词干算法有时会错误地混淆单词或通过删除后缀来更改单词的含义。

  • 词干形式通常不是合适的词,因此字段中的术语对于创建拼写词典之类的事情没有用处。

变化

尽管词干以基本形式对索引中的单词进行编码,但当您使用变体时,您会将单词“原样”编入索引,并且 at query time 使用启发式算法在用户查询中展开单词,以生成单词的形态变化。

>>> from whoosh.lang.morph_en import variations
>>> variations("rendered")
set(['rendered', 'rendernesses', 'render', 'renderless', 'rendering',
'renderness', 'renderes', 'renderer', 'renderements', 'rendereless',
'renderenesses', 'rendere', 'renderment', 'renderest', 'renderement',
'rendereful', 'renderers', 'renderful', 'renderings', 'renders', 'renderly',
'renderely', 'rendereness', 'renderments'])

对于一个给定的单词,许多生成的变体将不是有效的单词,但是对于whoosh来说,检查索引中实际存在哪些变体并只搜索那些变体是相当快的。

这个 whoosh.query.Variations 查询对象允许您搜索单词的变体。而正常 whoosh.query.Term 对象只搜索给定的术语, Variations 查询的作用类似于 Or 查询索引中给定单词的变体。例如,查询:

query.Variations("content", "rendered")

…可能会这样(取决于索引中的单词)::

query.Or([query.Term("content", "render"), query.Term("content", "rendered"),
          query.Term("content", "renders"), query.Term("content", "rendering")])

使用查询分析器 whoosh.query.Variations 而不是 whoosh.query.Term 对于个别术语,请使用 termclass 分析器初始化方法的关键字参数::

from whoosh import qparser, query

qp = qparser.QueryParser("content", termclass=query.Variations)

变化有利弊。

  • 它允许用户查找文档而不必担心单词形式。

  • 字段中的术语是实际单词,而不是词干,因此您可以将字段的内容用于其他目的,如拼写检查查询。

  • 它增加了索引相对于词干的大小,因为不同的单词形式是单独索引的。

  • 它像一个 Or 搜索所有的变化,这比搜索单个词慢。

词形还原

尽管词干是一种“蛮力”,机械地尝试使用简单的规则将单词还原为其基本形式,但词形还原通常指使用语言模型找到单词基本形式(“lemma”)的更复杂的方法,通常包括分析周围环境和部分语音标记。

whoosh不包含任何词形还原函数,但是如果您有单独的词形还原代码,则可以编写自定义的 whoosh.analysis.Filter 把它集成到一个Whoosh分析器中。

字符折叠

例如,您可以设置一个要处理的分析器, áaåâ 相当于提高召回率。这通常非常有用,例如,允许用户键入 caferesume 并查找包含 caféresumé .

字符折叠对于可能出现在亚洲语言文本中的Unicode字符尤其有用,这些字符应被视为等同于其ASCII等价字符,例如“半宽”字符。

字符折叠并不总是一种灵丹妙药。有关重音折叠可以分解的地方的注意事项,请参阅本文。

http://www.alistapart.com/articles/accent-folding-for-auto-complete/

whoosh包括几个向分析器添加字符折叠的机制。

这个 whoosh.analysis.CharsetFilter 将字符映射应用于标记文本。例如,它将筛选令牌 u'café', u'resumé', ...u'cafe', u'resume', ... . 这通常是您想要使用的方法,除非您需要使用字符集来标记术语:

from whoosh.analysis import CharsetFilter, StemmingAnalyzer
from whoosh import fields
from whoosh.support.charset import accent_map

# For example, to add an accent-folding filter to a stemming analyzer:
my_analyzer = StemmingAnalyzer() | CharsetFilter(accent_map)

# To use this analyzer in your schema:
my_schema = fields.Schema(content=fields.TEXT(analyzer=my_analyzer))

这个 whoosh.analysis.CharsetTokenizer 使用Sphinx字符集表来分隔术语并执行字符折叠。这个标记器比 whoosh.analysis.RegexTokenizer 因为它在Python中循环遍历每个字符。如果您正在索引的语言可以使用正则表达式进行标记化,那么使用它将更快。 RegexTokenizerCharsetFilter 组合而不是使用 CharsetTokenizer .

这个 whoosh.support.charset 模块包含一个对大多数西方语言有用的重音折叠映射,以及一个更广泛的sphinx charset表和一个将sphinx charset表转换为 CharsetTokenizerCharsetFilter ::

# To create a filter using an enourmous character map for most languages
# generated from a Sphinx charset table
from whoosh.analysis import CharsetFilter
from whoosh.support.charset import default_charset, charset_table_to_dict
charmap = charset_table_to_dict(default_charset)
my_analyzer = StemmingAnalyzer() | CharsetFilter(charmap)

(斯芬克斯字符集表格格式见http://www.sphinxsearch.com/docs/current.html conf charset table)