whoosh和jieba实现中文全文检索
截止目前(2018-8-5), Whoosh 项目已经整整一年没有更新(最后提交于 2017-07-16),作者可能已经弃坑。
简介
Whoosh 是一个纯 Python 实现的全文检索引擎,虽然不如 Elasticsearch ,但好处是纯 Python 实现易于集成,在小项目中应用广泛。
Whoosh 自带的分词器不支持中文分词。 jieba 是一个中文分词组件,实现了一个供 Whoosh 调用的中文分词器。两者结合使用即可以实现中文全文检索。
快速上手
环境准备
|
|
简单示例
|
|
输出结果:
|
|
创建 Schema
使用 Whoosh 进行检索需要创建索引对象(index object),而索引对象的结构由 Schema 定义。
Schema 会列出索引对象的字段(field),字段是文档(document)中的一条信息,例如标题或者文本内容。字段可以通过参数,设置是否被搜索,是否在搜索结果中与被索引的字段一起返回。
类比 SQL 数据库表:
Whoosh 索引 | SQL 数据库表 |
---|---|
Schema | 表结构 |
field 字段 | 字段 field |
document 文档 | 记录 record |
索引对象 | 整个表 |
举个例子:
|
|
上面的代码创建了一个 Schema,由 title、id 和 content 三个 filed 组成。title 和 content 的类型为
TEXT
,id 的类型为
ID
。
Whoosh 中为 field 预定义了以下类型:
-
whoosh.fields.TEXT
用于正文。默认使用whoosh.analysis.StandardAnalyzer
分词并索引,但不在检索结果中返回。analyzer
参数指定分词器,stored
参数指定是否在检索结果中返回,phrase
参数指定是否允许分词检索。 -
whoosh.fields.KEYWORD
用于以空格或逗号分隔的关键字。默认索引,不在检索结果中返回,不能分词。 -
whoosh.fields.ID
用于日期、路径、URL,分类等等。字段的值作为整体被索引,默认不返回,不能分词。 -
whoosh.fields.STORED
用于在检索结果中展示的信息。不会被索引且无法检索,会在检索结果中返回。 -
whoosh.fields.NUMERIC
用于数字,可以存储整数或浮点数。 -
whoosh.fields.DATETIME
用于datetime
对象。 -
whoosh.fields.BOOLEAN
用于布尔值。
其中
TEXT
和
ID
比较常用。
创建索引
有了 Schema 之后,就可以通过 Schema 创建索引。Whoosh 的索引使用文件存储,创建时传入目录名,索引文件就会存储在该目录下。
|
|
exists_in
返回目录下是否存在索引,
create_in
创建索引。如果在一个已经存在索引文件的目录下调用
create_in
创建索引,原索引会丢失。
exists_in
和
create_in
函数都可以传入
indexname
参数,指定创建的索引名称。
添加文档
有了索引对象后,就可以添加文档数据到索引中。
首先,获取索引对象:
|
|
open_dir
函数用于从指定目录中获取索引对象,该函数也可以传入
indexname
参数指定索引名称。
通过索引对象新建一个 IndexWriter 对象,该对象会锁住索引以进行写入,保证同时只有一个进程/线程进行写操作。
|
|
通过该 IndexWriter 对象的
add_document
方法添加 document,该方法接受关键字参数,与 Schema 定义保持一致。
|
|
所有 docment 添加完成后,调用
commit
方法写入索引。
|
|
检索结果
首先通过索引对象创建一个 Searcher 对象,该对象使用完成后应该被关闭,可以使用 Python 中的
with
语法。
|
|
可以直接使用
find
方法进行检索:
|
|
或者先构造 QueryParser 对象,再使用
search
方法检索:
|
|
search
方法可以使用
limit
参数指定返回结果的个数:
|
|
search_page
方法可以分页返回结果,默认每页 10 条结果,可以通过参数设置:
|
|
查询结果 results 对象类似 list,使用索引可以访问单个结果。
|
|
单个结果的
score
属性可以得到对该 document 的权重评分,
highlights
方法可以对指定 field 中的检索词进行高亮(加 b 标签)。
|
|
在 Flask 中使用 Whoosh
在 Flask 中使用 Whoosh 最好用的扩展是 Flask-WhooshAlchemy ,与 Flask-SQLAlchemy 无缝集成。可以直接索引数据库中的记录并通过数据库查询检索。
但这个项目已经许久没有更新,PyPI 上的版本竟然不支持 Python3,这里推荐使用从 Flask-WhooshAlchemy fork 开发的 Flask-WhooshAlchemyPlus 扩展,使用起来也非常简单,只需要以下步骤:
-
在 Flask 配置文件中定义
WHOOSH_BASE
,即 Whoosh 索引文件的存储路径; - 在定义数据库模型时指定 whoosh 索引字段和分词器;
-
调用扩展的
init_app(app)
方法初始化; -
在查询中使用
whoosh_search
进行检索,返回的结果为 query 对象,可以继续进行筛选,排序等,最后返回数据库记录;
详细请参考 Flask-WhooshAlchemyPlus 的文档。
Jieba 延迟加载机制
jieba 采用延迟加载,
import jieba
和jieba.Tokenizer()
不会立即触发词典的加载,一旦有必要才开始加载词典构建前缀字典。
由于此机制,在初次查询时才会触发词典加载(大约 1 秒钟时间)。我们可以手动加载词典:
|