关于分析器

概述

分析器是一个函数或可调用类(具有 __call__ 方法)获取一个Unicode字符串并返回一个标记生成器。通常“token”是一个词,例如字符串“mary had a little lamb”可能会产生tokens“mary”、“had”、“a”、“little”和“lamb”。然而,标记并不一定对应于单词。例如,您可以将中文文本标记为单个字符或双字。标记是索引的单位,也就是说,它们是您可以在索引中查找到的。

分析器基本上只是标记器和零个或更多过滤器的包装器。分析器 __call__ 方法将其参数传递给记号赋予器,记号赋予器通常被包装在一些过滤器中。

标记器是一个可调用的,它接受一个Unicode字符串并生成一系列 analysis.Token 物体。

例如,提供的 whoosh.analysis.RegexTokenizer 类实现了一个可自定义的、基于正则表达式的标记器,它提取单词并忽略空格和标点符号。

>>> from whoosh.analysis import RegexTokenizer
>>> tokenizer = RegexTokenizer()
>>> for token in tokenizer(u"Hello there my friend!"):
...   print repr(token.text)
u'Hello'
u'there'
u'my'
u'friend'

A filter is a callable that takes a generator of Tokens (either a tokenizer or another filter) and in turn yields a series of Tokens.

例如,提供的 whoosh.analysis.LowercaseFilter() 通过将标记的文本转换为小写来筛选标记。实现非常简单:

def LowercaseFilter(tokens):
    """Uses lower() to lowercase token text. For example, tokens
    "This","is","a","TEST" become "this","is","a","test".
    """

    for t in tokens:
        t.text = t.text.lower()
        yield t

您可以将过滤器包裹在标记器周围,以查看其运行情况:

>>> from whoosh.analysis import LowercaseFilter
>>> for token in LowercaseFilter(tokenizer(u"These ARE the things I want!")):
...   print repr(token.text)
u'these'
u'are'
u'the'
u'things'
u'i'
u'want'

分析器只是一种将记号赋予器和一些过滤器组合成单个包的方法。

You can implement an analyzer as a custom class or function, or compose tokenizers and filters together using the | 性状:

my_analyzer = RegexTokenizer() | LowercaseFilter() | StopFilter()

第一项必须是标记器,其余项必须是筛选器(不能将筛选器放在第一项之后,也不能将标记器放在第一项之后)。注意,这只在标记器至少是 whoosh.analysis.Composable 就像所有的标记化器和过滤器一样。

whoosh.analysis 有关随whoosh一起提供的可用分析仪、标记器和过滤器的信息模块。

使用分析器

在架构中创建字段时,可以将分析器指定为字段对象的关键字参数::

schema = Schema(content=TEXT(analyzer=StemmingAnalyzer()))

高级分析

令牌对象

这个 Token 类没有方法。它只是一个记录某些属性的地方。一 Token 对象实际上有两种属性: settings 那记录什么样的信息 Token 对象包含或应该包含,并且 information 关于当前令牌。

令牌设置属性

A Token 对象应始终具有以下属性。标记器或过滤器可以检查这些属性,以查看可用的信息类型和/或它们应该在 Token 对象。

这些属性由记号赋予器根据从分析器传递给它的参数在创建记号时设置。

过滤器 should not 更改这些属性的值。

类型 属性名 描述 违约
STR 模式 The mode in which the analyzer is being called, e.g. 'index' during indexing or 'query' during query parsing
布尔 位置 是否在令牌中记录定期头寸
布尔 字符 是否在令牌中记录术语开始和结束字符索引
布尔 升压 Whether per-term boosts are recorded in the token
布尔 拆线 是否应从令牌流中删除停止字

Token information attributes

A Token 对象可以具有以下任何属性。这个 text 属性应始终存在。原始属性可以由记号赋予器设置。所有其他属性只能根据上述“设置”属性的值进行访问或设置。

类型 名字 描述
统一码 文本 令牌的文本(此文本应始终存在)
统一码 起初的 The original (pre-filtered) text of the token. The tokenizer may record this, and filters are expected not to modify it.
利息 销售时点情报系统 令牌在流中的位置,从0开始(仅当位置为真时设置)
利息 斯塔查尔 原始字符串中标记开头的字符索引(仅当chars为true时设置)
利息 内膜 原始字符串中标记结尾的字符索引(仅当chars为true时设置)
浮动 促进 此令牌的提升(仅当提升为真时设置)
布尔 停止 此令牌是否为“停止”字(仅在removestops为false时设置)

那么,为什么大多数信息属性是可选的呢?不同的字段格式需要关于每个令牌的不同级别的信息。例如, Frequency 格式只需要标记文本。这个 Positions 格式记录术语位置,因此它需要在 Token . 这个 Characters 格式记录术语位置和每个术语的开始和结束字符索引,因此它需要它们在令牌上,等等。

这个 Format 表示每个字段格式的对象调用该字段的分析器,并传递与所需信息类型对应的参数,例如:

analyzer(unicode_string, positions=True)

然后,分析器可以将该信息传递给标记器,以便标记器初始化 Token 它生成的对象。

对索引和查询分析执行不同的分析

Whoosh mode 设置属性以指示索引器是否正在调用分析器( mode='index' )或查询分析器( mode='query' )如果您只希望在索引或查询分析时应用转换,则此功能非常有用:

class MyFilter(Filter):
    def __call__(self, tokens):
        for t in tokens:
            if t.mode == 'query':
                ...
            else:
                ...

这个 whoosh.analysis.MultiFilter 筛选器类允许您根据模式设置指定要使用的不同筛选器:

intraword = MultiFilter(index=IntraWordFilter(mergewords=True, mergenums=True),
                        query=IntraWordFilter(mergewords=False, mergenums=False))

停用词

“停止”字是非常常见的字,索引它们通常会适得其反,例如“and”、“or”、“if”等。 analysis.StopFilter 允许您筛选出停止词,并包括常用停止词的默认列表。

>>> from whoosh.analysis import StopFilter
>>> stopper = StopFilter()
>>> for token in stopper(LowercaseFilter(tokenizer(u"These ARE the things I want!"))):
...   print repr(token.text)
u'these'
u'things'
u'want'

然而,这个看似简单的过滤概念引发了一些小但有点棘手的问题:重新编号术语位置和保留或删除停止的单词。

重新编号术语位置

请记住,有时要求分析器记录令牌流中每个令牌的位置:

Token.text 乌玛丽 乌拉德 乌亚 乌兰姆
Token.pos 0 1 2 3

所以发生了什么 pos 令牌的属性,如果 StopFilter 删除单词 hada 从小溪里?它是否应该重新编号位置,假装“停止”的词从未存在?即。:

Token.text 乌玛丽 乌兰姆
Token.pos 0 1

还是应该保留单词的原始位置?即:

Token.text 乌玛丽 乌兰姆
Token.pos 0 3

事实证明,不同的情况需要不同的解决方案,因此 StopFilter 类支持上述两种行为。重新编号是默认的,因为这通常是最有用的,并且是支持短语搜索所必需的。但是,可以在stopfilter的构造函数中设置一个参数,告诉它不要对位置重新编号:

stopper = StopFilter(renumber=False)

删除或留下停止语

使用要点 StopFilter 是删除停止词,对吗?实际上,在某些情况下,您可能希望将令牌标记为“已停止”,但不从令牌流中删除它们。

例如,如果您正在编写自己的查询分析器,则可以通过字段分析器运行用户的查询,将其分解为标记。在这种情况下,您可能希望知道哪些单词是“已停止”的,以便向最终用户提供有用的反馈(例如,“以下单词太常见,无法搜索:”)。

在其他情况下,您可能希望在流中为某些筛选步骤保留已停止的字(例如,您可能有一个步骤查看以前的令牌,并希望已停止的令牌成为进程的一部分),但稍后将其删除。

这个 analysis 模块提供了一些工具来保存和删除流中的停止字。

这个 removestops parameter passed to the analyzer's __call__ 方法(并复制到 Token 对象作为属性)指定是否应从流中删除停止字或将其留在中。

>>> from whoosh.analysis import StandardAnalyzer
>>> analyzer = StandardAnalyzer()
>>> [(t.text, t.stopped) for t in analyzer(u"This is a test")]
[(u'test', False)]
>>> [(t.text, t.stopped) for t in analyzer(u"This is a test", removestops=False)]
[(u'this', True), (u'is', True), (u'a', True), (u'test', False)]

这个 analysis.unstopped() filter函数接受一个令牌生成器并只生成 stopped 属性是 False .

注解

即使在用于索引的分析器中保留流中的已停止字,索引器也会忽略 stopped 属性是 True .

实施说明

因为对象创建在python中很慢,所以stock tokenizer不会创建新的 analysis.Token 每个令牌的对象。相反,他们创造了一个 Token 反对并反复屈服。这是一个很好的性能快捷方式,但如果代码试图记住生成器循环之间的标记,则可能导致奇怪的行为。

因为分析仪只有一个 Token 对象,它不断更改属性,如果保留从生成器循环中获取的令牌的副本,则它将从您的下面更改。例如::

>>> list(tokenizer(u"Hello there my friend"))
[Token(u"friend"), Token(u"friend"), Token(u"friend"), Token(u"friend")]

相反,请执行以下操作:

>>> [t.text for t in tokenizer(u"Hello there my friend")]

也就是说,保存属性,而不是令牌对象本身。

如果将自己的标记器、过滤器或分析器实现为类,则应实现 __eq__ 方法。这对于比较 Schema 物体。

Token 物体并不特别优雅。如果我有更好的想法,我可能会改变它。;)任何东西都不要求通过调用标记器和过滤器来实现分析器。标记化器和过滤器只是构造代码的一种简单方法。只要分析器实现,您就可以随意编写它。 __call__ .