概览
Whoosh是一个用来索引文本并能根据索引搜索的的包含类和方法的类库。它允许你开发一个针对自己内容的搜索引擎。例如,如果你想创建一个博客软件,你可以使用Whoosh添加一个允许用户搜索博客类目的搜索功能。
使用入门
index,schema,field
当开始使用Whoosh时,你需要一个索引的对象。第一次使用时,你需要创建一个索引,并同时定义一个索引的schema。schema中要列出索引需要的字段。
一个字段是索引中的每个文档的一类信息,例如标题或文档内容。一个字段可以同时被储存并索引,也可以只有其中之一(被索引意味着可以被搜索;被存储意味着获得索引的值与结果一起返回,这个特性在字段是一个标题时比较有用)。
下面这个schema有两个字段, “title”和“content”:
from whoosh.fields import Schema, TEXT
schema = Schema(title=TEXT, content=TEXT)
当你创建索引时,你只需要创建一次schema。schema会被序列化并存储到索引中。
当你创建一个schema对象,使用关键字参数将字段名称映射到字段类型。字段及其类型的列表定义了索引和可搜索的内容。Whoosh预定义了很多比较有用的字段类型,你也可以很容易的定义自己的。
whoosh.fields.ID
此类型简单地将全部字段的值(不被截断)作为一个单元来索引(并可选是否存储存储),这个特性在地址,URK,日期,类型等字段时十分有用。
whoosh.fields.STORED
这个字段与文档一起使用,不是索引的。这个字段类型不可以被索引和被搜索。在用户获得搜索结果时,你想要如何展示文档信息。
whoosh.fields.KEYWORD
这个类型是为空间或逗号分隔关键字设计的。这个类型可以被索引和搜索(可选是否被存储)。也就是说,它不支持短语搜索。
whoosh.fields.TEXT
This type is for body text. It indexes (and optionally stores) the text and stores term positions to allow phrase searching.
这个是文件内容类型。它索引(可选是否被存储)文本和存储术语位置以允许短语搜索。
whoosh.fields.NUMERIC
数字类型,存储整数和浮点数
whoosh.fields.BOOLEAN
布尔类型
whoosh.fields.DATETIME
时间对象
whoosh.fields.NGRAM
and whoosh.fields.NGRAMWORDS
这些类型将字段文本或单个术语分解成n元。有关更多信息,请参阅索引和搜索n-克。
也可以精简一下,如果你不需要传任何参数给字段类型,你可以只给定一个类名,然后Whoosh将会返回一个实例对象给你
代码示例如下
from whoosh.fields import Schema, STORED, ID, KEYWORD, TEXT
schema = Schema(title=TEXT(stored=True), content=TEXT,
path=ID(stored=True), tags=KEYWORD, icon=STORED)
当你有了一个Schema,你就可以创建一个索引了
import os.path
from whoosh.index import create_in
if not os.path.exists("index"):
os.mkdir("index")
ix = create_in("index", schema)
如果要求较低,这里已经创建了一个包含索引的存储对象。一个存储对象就代表索引存储在其中。通常它是一个文件存储,它将索引存储为目录中的一组文件。
当你创建一个索引之后,可以使用比较便利的方法open_dir
打开它
from whoosh.index import open_dir
ix = open_dir("index")
IndexWriter对象
ok,现在我们有了一个索引对象,现在我们开始添加文档。索引对象的writer方法返回一个IndexWriter对象,它可以让你添加一个文档到索引中。IndexWriter的add_document(**kwargs)方法接受字段名称映射到VALU的关键字参数
writer = ix.writer()
writer.add_document(title=u"My document", content=u"This is my document!",
path=u"/a", tags=u"first short", icon=u"/icons/star.png")
writer.add_document(title=u"Second try", content=u"This is the second example.",
path=u"/b", tags=u"second short", icon=u"/icons/sheep.png")
writer.add_document(title=u"Third time's the charm", content=u"Examples are many.",
path=u"/c", tags=u"short", icon=u"/icons/book.png")
writer.commit()
重要提示
- 你并不需要填写所有字段的值,Whoosh并不关注你是否遗漏了文档中的一个字段。
- 被所以的文本字段必须传递unicode值,如果只是被存储,可以传递任何可以被序列化的对象。
如果你有一个文本字段纪要索引又要存储,你可以索引unicode值,但是如果需要的话,可以使用一个不同的对象来存储(通常不是这样,但有时这确实有用)。
writer.add_document(title=u"Title to be indexed", _stored_title=u"Stored title")
调用IndexWriter对象的commit方法将文档写入索引
writer.commit()
现在你的文档已经提交到索引中,你可以搜索他们了
Searcher对象
当开始搜索时,我们需要一个Searcher对象:
searcher = ix.searcher()
您通常希望使用with语句打开搜索器,这样在完成搜索时,搜索器将自动关闭(搜索对象表示打开文件数,所以,如果你不显示地关闭它们并且操作系统回收很慢,你会遇到文件句柄溢出)
with ix.searcher() as searcher:
下面的操作是等价的:
try:
searcher = ix.searcher()
...
finally:
searcher.close()
Searcher的search函数接受一个Query对象。你可以构建一个Query对象的字典或者用Parser解析查询语句。
例如:这个查询将匹配出content字段中包含“apple”和“bear”的文档
from whoosh.query import *
myquery = And([Term("content", u"apple"), Term("content", "bear")])
若要解析查询字符串,可以使用QPARSER模块中的默认查询解析器。第一个参数是要搜索的默认字段。经常用于文本内容字段。第二个可选参数是用于理解如何解析字段的schema。
from whoosh.qparser import QueryParser
parser = QueryParser("content", ix.schema)
myquery = parser.parse(querystring)
当你有了一个Searcher和一个query的对象,你可以用Searcher的search()函数执行一个查询并得到一个搜索结果对象。
results = searcher.search(myquery)
print(len(results))
1
print(results[0])
输出
{"title": "Second try", "path": "/b", "icon": "/icons/sheep.png"}
默认的QueryParser实现了与Lucene非常相似的查询语言。它允许你使用AND或OR连接语句,使用NOT排除语句,将语句组合成带括号的子句,执行范围、前缀和通配符查询,并指定要搜索的不同字段。默认情况下,它将子句与AND结合在一起(因此,默认情况下,您指定的所有术语必须在文档中才能匹配):
print(parser.parse(u"render shade animate"))
And([Term("content", "render"), Term("content", "shade"), Term("content", "animate")])
print(parser.parse(u"render OR (title:shade keyword:animate)"))
Or([Term("content", "render"), And([Term("title", "shade"), Term("keyword", "animate")])])
print(parser.parse(u"rend*"))
Prefix("content", "rend")
对于搜索结果,whoosh还有一些扩展特性
- 用索引字段的值来排序结果,而不是通过Relelvices进行排序。
- 在原始文档摘录中突出搜索词。
- 基于查询出的文档扩展查询语句。
- 将结果分页(例如“显示结果1-20,第4页第1页”)
下面是一个完整的例子:
from whoosh.index import create_in
from whoosh.fields import *
schema = Schema(title=TEXT(stored=True), path=ID(stored=True), content=TEXT)
ix = create_in("indexdir", schema)
writer = ix.writer()
writer.add_document(title=u"First document", path=u"/a", content=u"This is the first document we've added!")
writer.add_document(title=u"Second document", path=u"/b",content=u"The second one is even more interesting!")
writer.commit()
from whoosh.qparser import QueryParser
with ix.searcher() as searcher:
query = QueryParser("content", ix.schema).parse("first")
results = searcher.search(query)
results[0]