如何创建突出显示的搜索结果摘要

概述

突出显示系统作为管道工作,有四种组件类型。

  • Fragmenters 根据文本中匹配词的位置,将原始文本切碎为片段。

  • Scorers 为每个片段分配一个分数,允许系统根据任何标准对最佳片段进行排序。

  • Order functions 控制向用户显示得分最高的片段的顺序。例如,您可以按照片段在文档中出现的顺序(第一个)显示片段,或者先显示得分较高的片段(得分)

  • Formatters 将片段对象转换为人类可读的输出,例如HTML字符串。

要求

突出显示要求索引文档的文本可用。您可以将文本保存在存储字段中,或者如果原始文本在文件、数据库列等中可用,只需快速重新加载即可。请注意,您可能需要处理要删除的文本,例如HTML标记、wiki标记等。

如何

获取搜索结果:

results = mysearcher.search(myquery)
for hit in results:
    print(hit["title"])

你可以使用 highlights() 方法在 whoosh.searching.Hit 对象获取包含搜索词的文档中突出显示的代码段。

第一个参数是要突出显示的字段的名称。如果存储了字段,则只需提供以下参数:

results = mysearcher.search(myquery)
for hit in results:
    print(hit["title"])
    # Assume "content" field is stored
    print(hit.highlights("content"))

如果未存储字段,则需要以其他方式检索字段的文本。例如,从原始文件或数据库读取它。然后您可以提供要突出显示的文本 text 论点:

results = mysearcher.search(myquery)
for hit in results:
    print(hit["title"])

    # Assume the "path" stored field contains a path to the original file
    with open(hit["path"]) as fileobj:
        filecontents = fileobj.read()

    print(hit.highlights("content", text=filecontents))

字符限制

默认情况下,whoosh只从文本的前32K字符中提取片段。这可以防止非常长的文本过多地阻碍突出显示过程,而且通常是合理的,因为重要/摘要信息通常在文档的开头。但是,如果您发现突出显示缺少信息(例如,术语出现在后面一节中的非常长的百科全书文章),则可以增加碎片的字符限制。

您可以这样更改results对象的字符限制:

results = mysearcher.search(myquery)
results.fragmenter.charlimit = 100000

要关闭字符限制:

results.fragmenter.charlimit = None

如果实例化自定义片段器,则可以直接对其设置字符限制:

sf = highlight.SentenceFragmenter(charlimit=100000)
results.fragmenter = sf

有关自定义突出显示的信息,请参见下文。

如果增加或禁用字符限制以突出显示长文档,则可能需要使用下面“加快突出显示速度”部分中的提示以加快突出显示速度。

自定义突出显示

碎片数量

你可以使用 top 用于控制每个代码段中返回的片段数的关键字参数::

# Show a maximum of 5 fragments from the document
print hit.highlights("content", top=5)

碎片大小

默认碎片器具有 maxchars 控制片段最大长度的属性(默认值200),以及 surround 属性(默认值20),控制要在片段开头和结尾添加的上下文的最大字符数:

# Allow larger fragments
results.fragmenter.maxchars = 300

# Show more context before and after
results.fragmenter.surround = 50

碎片化者

片段器控制如何从原始文本中提取摘录。

这个 highlight 模块具有以下预制碎片:

whoosh.highlight.ContextFragmenter (默认)

这是一个“聪明”的片段器,它找到匹配的词,然后拉入环绕文本形成片段。这个片段器只生成包含匹配项的片段。

whoosh.highlight.SentenceFragmenter

尝试根据句子标点符号(“.”,“!”将文本拆分为片段。和“?”。此对象通过在原始文本中查找句尾作为每个标记的“endchar”后的下一个字符来工作。可能被源代码、小数等愚弄。

whoosh.highlight.WholeFragmenter

将整个文本作为一个“片段”返回。如果突出显示的是一小段文本,而不需要对其进行分段,那么这将非常有用。

不同的碎片有不同的选择。例如,默认 ContextFragmenter 允许您在任意一侧设置要添加的最大片段大小和上下文大小:

my_cf = highlight.ContextFragmenter(maxchars=100, surround=30)

whoosh.highlight 有关详细信息,请参阅文档。

要使用不同的碎片器:

results.fragmenter = my_cf

记分员

记分员是一个需要 whoosh.highlight.Fragment 对象并返回可排序的值(值越大表示片段越好)。默认的记分员将片段中匹配的术语数相加,并为不同匹配的术语数加上“奖金”。突出显示系统使用此分数选择要向用户显示的最佳片段。

作为自定义记分员的一个例子,用片段中匹配项位置的最低标准偏差对片段进行排序:

def StandardDeviationScorer(fragment):
    """Gives higher scores to fragments where the matched terms are close
    together.
    """

    # Since lower values are better in this case, we need to negate the
    # value
    return 0 - stddev([t.pos for t in fragment.matched])

使用不同的记分员:

results.scorer = StandardDeviationScorer

秩序

order是一个函数,它获取一个片段并返回一个可排序的值,该值用于在将得分最高的片段呈现给用户之前对其进行排序(其中值较低的片段出现在值较高的片段之前)。

这个 highlight 模块具有以下顺序功能。

FIRST (默认)

按片段在文档中的显示顺序显示片段。

SCORE

首先显示得分最高的片段。

这个 highlight 模块还包括 LONGER (先是较长的碎片)和 SHORTER (首先是较短的片段),但它们可能没有一般的用处。

使用不同的顺序:

results.order = highlight.SCORE

格式化程序

格式化程序控制如何将得分最高的片段转换为格式化的文本位以供用户显示。它可以返回任何内容(例如纯文本、HTML、genshi事件流、SAX事件生成器或对调用系统有用的任何其他内容)。

这个 highlight 模块包含以下预制格式化程序。

whoosh.highlight.HtmlFormatter

输出一个字符串,该字符串包含匹配项周围的HTML标记(具有类属性)。

whoosh.highlight.UppercaseFormatter

将匹配的术语转换为大写。

whoosh.highlight.GenshiFormatter

输出一个genshi事件流,匹配的术语包装在一个可配置元素中。

创建自定义格式化程序的最简单方法是子类 highlight.Formatter 并覆盖 format_token 方法:

class BracketFormatter(highlight.Formatter):
    """Puts square brackets around the matched terms.
    """

    def format_token(self, text, token, replace=False):
        # Use the get_text function to get the text corresponding to the
        # token
        tokentext = highlight.get_text(text, token, replace)

        # Return the text as you want it to appear in the highlighted
        # string
        return "[%s]" % tokentext

要使用其他格式化程序:

brf = BracketFormatter()
results.formatter = brf

如果您需要对格式进行更多的控制(或者希望输出字符串以外的内容),则需要重写其他方法。有关 whoosh.highlight.Formatter 班级。

高亮对象

您可以创建一个可重用的 whoosh.highlight.Highlighter 对象。关键字参数允许您更改 fragmenterscorerorder 和/或 formatter ::

hi = highlight.Highlighter(fragmenter=my_cf, scorer=sds)

然后您可以使用 whoosh.highlight.Highlighter.highlight_hit() 获取突出显示的方法 Hit 对象:

for hit in results:
    print(hit["title"])
    print(hi.highlight_hit(hit))

(当您分配给 Results 对象的 fragmenterscorerorderformatter attributes, you're actually changing the values on the results object's default Highlighter 对象。

加快突出显示

记录搜索过程中与哪些文档匹配的术语可能会使突出显示更快,因为它将跳过已知的文档,在给定字段中不包含任何匹配的术语::

# Record per-document term matches
results = searcher.search(myquery, terms=True)

PinpointFragmenter

通常,突出显示系统使用字段的分析器重新标记文档的文本,以便在上下文中找到匹配的术语。如果您有较长的文档,并且增加/禁用了字符限制,和/或如果字段具有非常复杂的分析器,则重新标记化可能很慢。

whoosh可以在索引中查找匹配项的字符位置,而不是重新定义。查找字符位置不是即时的,但通常比分析大量文本要快。

使用 whoosh.highlight.PinpointFragmenter 并且避免重新标记文档文本,必须执行以下所有操作:

用字符信息为字段编制索引(这将需要对现有索引重新编制索引)::

# Index the start and end chars of each term
schema = fields.Schema(content=fields.TEXT(stored=True, chars=True))

在结果中记录每个文档的术语匹配:

# Record per-document term matches
results = searcher.search(myquery, terms=True)

设置一个 whoosh.highlight.PinpointFragmenter 作为碎片破片者:

results.fragmenter = highlight.PinpointFragmenter()

精确定位碎片中心限制

当突出显示系统不重新标记文本时,它不知道文本中除了在索引中查找的匹配词之外还有其他任何词。因此,当碎片添加周围的上下文时,它只是盲目地添加或添加一定数量的字符,因此无法区分内容和空白,或打破单词边界,例如:

>>> hit.highlights("content")
're when the <b>fragmenter</b>\n       ad'

(当单词片段形成脏字时,这可能会使人感到尴尬!)

避免这种情况的一种方法是不显示任何周围的上下文,但是包含一个匹配项的片段将只包含该匹配项::

>>> hit.highlights("content")
'<b>fragmenter</b>'

或者,在将文本传递给突出显示系统之前,可以规范化文本中的空白:

>>> text = searcher.stored_
>>> re.sub("[\t\r\n ]+", " ", text)
>>> hit.highlights("content", text=text)

……并使用 autotrim 选择权 PinpointFragmenter 自动删除片段中第一个空格之前和最后一个空格之后的文本:

>>> results.fragmenter = highlight.PinpointFragmenter(autotrim=True)
>>> hit.highlights("content")
'when the <b>fragmenter</b>'

使用低级API

使用

以下函数允许您使用分析器重新唤醒和突出显示一段文本:

from whoosh.highlight import highlight

excerpts = highlight(text, terms, analyzer, fragmenter, formatter, top=3,
                     scorer=BasicFragmentScorer, minscore=1, order=FIRST)
text

文档的原始文本。

terms

包含要匹配的查询词的序列或集合,例如 ("render", "shader").

analyzer

用于将文档文本拆分为标记以与查询词匹配的分析器。这通常是查询词所在字段的分析器。

fragmenter

A whoosh.highlight.Fragmenter 对象,见下文。

formatter

A whoosh.highlight.Formatter 对象,见下文。

top

The number of fragments to include in the output.

scorer

A whoosh.highlight.FragmentScorer 对象。目前包含在whoosh中的唯一得分者是 BasicFragmentScorer 默认情况下。

minscore

必须考虑碎片的最低分数才能包含在内。

order

确定输出文本中“顶部”片段顺序的排序函数。