设计模式

关于架构和字段

模式指定索引中文档的字段。

每个文档可以有多个字段,如标题、内容、URL、日期等。

一些字段可以被索引,一些字段可以与文档一起存储,这样字段值在搜索结果中可用。某些字段将同时被索引和存储。

模式是文档中所有可能字段的集合。每个单独的文档可能只使用模式中可用字段的子集。

例如,用于为电子邮件编制索引的简单模式可能具有如下字段 from_addrto_addrsubjectbodyattachments 那里 attachments field lists the names of attachments to the email. For emails without attachments, you would omit the attachments field.

内置字段类型

whoosh提供了一些有用的预定义字段类型:

whoosh.fields.TEXT

此类型用于正文文本。它索引(并可选地存储)文本并存储术语位置,以允许短语搜索。

TEXT 字段使用 StandardAnalyzer 默认情况下。要指定其他分析器,请使用 analyzer 构造函数的关键字参数,例如 TEXT(analyzer=analysis.StemmingAnalyzer()) . 见 关于分析器 .

默认情况下, TEXT 字段存储每个索引项的位置信息,以允许您搜索短语。如果不需要在文本字段中搜索短语,可以关闭存储术语位置以节省空间。使用 TEXT(phrase=False) .

默认情况下, TEXT 不存储字段。通常,您不希望在搜索索引中存储正文文本。通常,索引文档本身可以根据搜索结果进行读取或链接,因此不需要将它们的文本存储在搜索索引中。但是,在某些情况下,它是有用的(参见 如何创建突出显示的搜索结果摘要 )使用 TEXT(stored=True) 指定文本应存储在索引中。

whoosh.fields.KEYWORD

此字段类型是为空格或逗号分隔的关键字设计的。此类型是可索引和搜索的(并且可以选择存储)。为了节省空间,它不支持短语搜索。

要将字段值存储在索引中,请使用 stored=True 在构造函数中。要在索引关键字之前自动将其小写,请使用 lowercase=True .

默认情况下,关键字是空格分隔的。要用逗号分隔关键字(允许包含空格的关键字),请使用 commas=True .

如果用户将使用关键字字段进行搜索,请使用 scorable=True .

whoosh.fields.ID

这个 ID 字段类型只是将字段的整个值作为一个单元进行索引(并可选地存储)(也就是说,它不会将字段分解为单个术语)。这种类型的字段不存储频率信息,所以它非常紧凑,但对于评分来说不是很有用。

使用 ID 对于url或path(文档的url或文件路径)、date、category等字段,这些字段的值必须作为一个整体来处理,并且每个文档的字段只有一个值。

默认情况下, ID 不存储字段。使用 ID(stored=True) 指定字段值应与文档一起存储,以便在搜索结果中使用。例如,您希望存储URL字段的值,以便在搜索结果中提供指向原始字段的链接。

whoosh.fields.STORED
此字段与文档一起存储,但未编入索引且不可搜索。这对于要在搜索结果中显示给用户的文档信息很有用,但不需要能够搜索。
whoosh.fields.NUMERIC
此字段以紧凑、可排序的格式存储int、long或浮点数字。
whoosh.fields.DATETIME
此字段以紧凑的可排序格式存储日期时间对象。
whoosh.fields.BOOLEAN
这个简单的文件索引了布尔值并允许用户搜索 yesnotruefalse10tf .
whoosh.fields.NGRAM
TBD。

专家用户可以创建自己的字段类型。

创建架构

创建架构:

from whoosh.fields import Schema, TEXT, KEYWORD, ID, STORED
from whoosh.analysis import StemmingAnalyzer

schema = Schema(from_addr=ID(stored=True),
                to_addr=ID(stored=True),
                subject=TEXT(stored=True),
                body=TEXT(analyzer=StemmingAnalyzer()),
                tags=KEYWORD)

如果没有为某个预定义字段指定任何构造函数关键字参数,则可以不使用括号(例如 fieldname=TEXT 而不是 fieldname=TEXT() )whoosh将为您实例化类。

或者,可以使用 SchemaClass 基类::

from whoosh.fields import SchemaClass, TEXT, KEYWORD, ID, STORED

class MySchema(SchemaClass):
    path = ID(stored=True)
    title = TEXT(stored=True)
    content = TEXT
    tags = KEYWORD

可以将声明类传递给 create_in()create_index() 而不是 Schema 实例。

索引后修改架构

创建索引后,可以使用 add_field()remove_field() 方法。这些方法在 Writer 对象:

writer = ix.writer()
writer.add_field("fieldname", fields.TEXT(stored=True))
writer.remove_field("content")
writer.commit()

(如果要修改模式 and 使用相同的编写器添加文档,必须调用 add_field() 和/或 remove_field before 您可以添加任何文档。)

这些方法也适用于 Index 对象作为方便,但当您在 Index ,index对象只创建编写器,对其调用相应的方法并提交,因此如果要添加或删除多个字段,则自己创建编写器的效率会更高:

ix.add_field("fieldname", fields.KEYWORD)

filedb 后端,删除字段只需从 schema --索引将不会变小,有关该字段的数据将保留在索引中,直到优化为止。优化将压缩索引,同时删除对已删除字段的引用::

writer = ix.writer()
writer.add_field("uuid", fields.ID(stored=True))
writer.remove_field("path")
writer.commit(optimize=True)

因为数据以字段名存储在磁盘上, do not 添加与已删除字段同名的新字段,而不优化以下两者之间的索引:

writer = ix.writer()
writer.delete_field("path")
# Don't do this!!!
writer.add_field("path", fields.KEYWORD)

(未来版本的whoosh可能会自动防止此错误。)

动态场

动态字段允许您将字段类型与任何与给定“glob”(包含 *? 和/或 [abc] 通配符)。

您可以使用 add() 方法与 glob keyword set to True:

schema = fields.Schema(...)
# Any name ending in "_d" will be treated as a stored
# DATETIME field
schema.add("*_d", fields.DATETIME(stored=True), glob=True)

要在现有索引上设置动态字段,请使用相同的 IndexWriter.add_field 方法,就像添加常规字段一样,但使用 glob 关键字参数设置为 True ::

writer = ix.writer()
writer.add_field("*_d", fields.DATETIME(stored=True), glob=True)
writer.commit()

要删除动态字段,请使用 IndexWriter.remove_field() 方法的名称为glob::

writer = ix.writer()
writer.remove_field("*_d")
writer.commit()

例如,允许文档包含以 _id 并将其与 ID 字段类型:

schema = fields.Schema(path=fields.ID)
schema.add("*_id", fields.ID, glob=True)

ix = index.create_in("myindex", schema)

w = ix.writer()
w.add_document(path=u"/a", test_id=u"alfa")
w.add_document(path=u"/b", class_id=u"MyClass")
# ...
w.commit()

qp = qparser.QueryParser("path", schema=schema)
q = qp.parse(u"test_id:alfa")
with ix.searcher() as s:
    results = s.search(q)

高级架构设置

场升压

可以为字段指定字段增强。这是一个乘数,适用于在该字段中找到的任何术语的分数。例如,要使标题字段中的术语得分是正文字段中术语的两倍,请执行以下操作:

schema = Schema(title=TEXT(field_boost=2.0), body=TEXT)

字段类型

上面列出的预定义字段类型是 fields.FieldType . FieldType 是一个非常简单的类。其属性包含定义字段行为的信息。

属性 类型 描述
格式 fields.Format 定义字段记录每个术语的信息类型,以及信息存储在磁盘上的方式。
矢量 fields.Format 可选:如果已定义,则存储此字段的每个文档转发索引信息的格式。
可评分的 布尔 如果为真,则每个文档中字段的长度(字数)存储在索引中。有点误称,因为并非所有评分都需要字段长度。但是,要从BM25F获得正确的结果,需要字段长度。
存储 布尔 如果为真,则此字段的值存储在索引中。
独特的 布尔 如果为true,则当用户调用时,此字段的值可用于替换具有相同值的文档。 document_update() 关于一个 IndexWriter .

大多数预定义字段类型的构造函数都有参数,您可以通过这些参数自定义这些部分。例如:

  • 大多数预定义的字段类型都采用设置fieldType.stored的存储关键字参数。
  • 这个 TEXT() 构造函数接受 analyzer 传递给格式化对象的关键字参数。

格式

A Format 对象定义字段记录每个术语的信息类型,以及信息存储在磁盘上的方式。

例如, Existence 格式将存储这样的日志:

doc  
10  
20  
30  

鉴于 Positions 格式将存储这样的日志:

doc 位置
10 [1,5,23]
20 [45]
30 [7,12]

索引代码将字段的Unicode字符串传递给字段的 Format 对象。这个 Format 对象调用其分析器(请参阅文本分析)将字符串拆分为标记,然后对每个标记的信息进行编码。

whoosh提供以下预先定义的格式。

类名 描述
存储 存储但未编入索引的字段的“空”格式。
存在 只记录术语是否在文档中,即不存储术语频率。对于标识符字段(如路径或ID)和“tag”类型字段很有用,其中频率应始终为0或1。
频率 存储每个术语在每个文档中出现的次数。
位置 存储每个术语在每个文档中出现的次数,以及出现在哪个位置。

这个 STORED 字段类型使用 Stored 格式(什么都不做,所以 STORED 字段没有索引)。这个 ID 类型使用 Existence 格式。这个 KEYWORD 类型使用 Frequency 格式。这个 TEXT 类型使用 Positions 如果它被实例化为 phrase=True (违约),或 Frequency 如果 phrase=False .

此外,为了方便专家用户,还实施了以下格式,但目前并未在whoosh中使用:

类名 描述
DocBoosts 就像存在一样,但每个文档的存储量也会增加
文字 与位置相同,但也存储每个术语的开始和结束字符索引
PositionBoosts 像 Positions ,但也存储每个位置的提升
CharacterBoosts 与位置类似,但也存储每个术语和每个位置提升的开始和结束字符索引

向量

主索引是反向索引。它将术语映射到它们出现的文档中。有时存储向前索引(也称为术语向量)也很有用,它将文档映射到文档中出现的术语。

例如,假设一个字段的倒排索引如下:

术语 帖子
苹果 [(doc=1, freq=2), (doc=2, freq=5), (doc=3, freq=1)]
[(doc=2, freq=7)]

相应的正向指数或术语向量为:

doc 帖子
1 [(text=apple, freq=2)]
2 [(text=apple, freq=5), (text='bear', freq=7)]
3 [(text=apple, freq=1)]

如果你设置 FieldType.vector 到A Format 对象,索引代码将使用 Format 对象来存储每个文档中有关术语的信息。目前,默认情况下,whoosh根本不使用术语向量,但对于希望实现自己字段类型的专家用户,它们是可用的。