赞
踩
whoosh 是一个纯python实现的全文搜索引擎,它小巧轻便,安装简单,设计上参考了 Lucene ,性能上虽有欠缺,但贵在方便,无需复杂安装,对于构建小型网站的搜索引擎来说,是一个不错的选择。 1. 快速入门 whoosh 可以使用pip进行安装 pip install whoosh 现在通过官网的例子,快速体验 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) print(results[0]) 程序最终输出结果为 <Hit {'path': '/a', 'title': 'First document'}> 官网上的例子,我没有做任何修改,只是添加了两行注释。整个程序分为两部分,第一部分是构建索引的过程,第二部分是搜索的过程。 2. 构建索引 2.1 倒排索引 搜索引擎的关键技术是建立倒排索引,倒排索引记录了哪些文档中包含了某个单词,比如 “酷python” 这个词出现在了你正在看的这篇文章中,假设这篇文章的编号是111, 那么索引中就会记录一条 酷python:111的记录。当你搜索 酷python 这个词的时候,搜索引擎从倒排索引中找到 酷python所对应的文档,如果有多个,搜索引擎则计算文档与搜索词的相关性,并根据相关性进行排序返回给你结果。 2.2 分词 我们在搜索时,所搜索的关键词可能是一个句子,文档里那么多内容,但索引只记录词与文档编号之间的映射关系,因此,不论是构建索引还是根据关键词进行搜索,都得进行分词。对于英语文档,分词是一件简单的事情,因为英语的句子是由若干个单次组成的。而中文的分词则相对复杂,因为我们的词是由单个汉字组成的,而词与词之间是没有空格这种明显的分界的,具体哪几个汉字组成一个词,要看所处的语境,比如 “ 军任命了一名中将 ”, 这里中将就是一个词,但在句子“ 产量三年中将增长两倍 ”, 中将 就不再是一个词。 但你大可不必担心,因为现在的中文分词技术已经非常成熟了,开源库jieba可以满足你绝大部分需求。 2.3 索引模式 现在要为100篇文章构建索引,一篇文章的信息可能包括 文章标题,内容,作者,在构建索引的时候,你需要定义索引模式,就如同定义一张mysql里的表,你需要指出需要存储哪些字段,以及这些字段的类型 from whoosh.fields import TEXT, SchemaClass from jieba.analyse import ChineseAnalyzer analyzer = ChineseAnalyzer() class ArticleSchema(SchemaClass): title = TEXT(stored=True, analyzer=analyzer) content = TEXT(stored=True, analyzer=analyzer) author = TEXT(stored=True, analyzer=analyzer) 与官网中的例子不同,我通过继承SchemaClass 来实现一个新的类,以此定义索引模式。而且我设置了analyzer 为ChineseAnalyzer, 这样whoosh就可以支持中文索引了,analyzer会对文档中的中文进行分词。 2.4 添加文档 schema = ArticleSchema() ix = create_in("indexdir", schema, indexname='article_index') writer = ix.writer() writer.add_document(title="登鹳雀楼", author="王之涣",content="白日依山尽,黄河入海流,欲穷千里目,更上一层楼") writer.add_document(title="登高", author="杜甫", content="风急天高猿啸哀,渚清沙白鸟飞回") writer.add_document(title="胡乱写的", author="黄河恋", content="展示效果") writer.commit() create_in 会创建一个名为indexdir 的文件夹,添加文档时,一定要根据你所定义的索引模式进行添加,这样就创建好了索引,添加文档的过程,就如同向mysql的表里写入数据。 3. 搜索 搜索的过程,需要使用open_dir函数打开索引文件,创建Searcher 对象 from whoosh.qparser import QueryParser from whoosh.index import open_dir ix = open_dir("indexdir", indexname='article_index') with ix.searcher() as searcher: query = QueryParser("content", ix.schema).parse("黄河") results = searcher.search(query) print(results[0]) 程序输出结果 <Hit {'author': '王之涣', 'content': '白日依山尽,黄河入海流,欲穷千里目,更上一层楼', 'title': '登鹳雀楼'}> 3.1 高亮显示 我们在百度搜索引擎搜索关键词所得到的结果,那些与关键词匹配的部分会被高亮显示,这样方便用户查看内容,这个功能,whoosh同样支持 with ix.searcher() as searcher: query = QueryParser("content", ix.schema).parse("黄河") results = searcher.search(query) data = results[0] text = data.highlights("content") print(text) 程序输出结果为 白日依山尽,<b class="match term0">黄河</b>入海流,欲穷千里目 在html文件中,你可以自己来定义match 和 term0 的样式。 3.2 多个字段同时搜索 对多个字段同时搜索,需要使用MultifieldParser from whoosh.qparser import QueryParser, MultifieldParser from whoosh.index import open_dir ix = open_dir("indexdir", indexname='article_index') with ix.searcher() as searcher: query = MultifieldParser(["content", 'author'], ix.schema).parse("黄河") results = searcher.search(query) for data in results: print(data) content中有黄河,或者author有黄河的文档,都可以被搜索出来,程序输出结果 <Hit {'author': '黄河恋', 'content': '展示效果', 'title': '胡乱写的'}> <Hit {'author': '王之涣', 'content': '白日依山尽,黄河入海流,欲穷千里目,更上一层楼', 'title': '登鹳雀楼'}> 3.3 多个关键词同时搜索 如果你所搜索的内容并不仅仅是一个关键词,而是多个,或者你搜索的是一个句子,搜索引擎会把你的句子进行分词,得到若干个词,这些词作为条件进行搜索,只有被搜索的字段同时满足这些关键词时,才能得到搜索结果,比如下面的搜索 query = MultifieldParser(["content", 'author'], ix.schema).parse("黄河 杜甫") 这个搜索条件不会得到任何结果,原因在于搜索条件等价于 ((content:黄河 OR author:黄河) AND (content:杜甫 OR author:杜甫)) 被搜索的字段中,比如同时包含黄河与杜甫。如果你希望这些关键词之间是或的关系,那么需要你自己来构建搜索条件 from whoosh.qparser import QueryParser, MultifieldParser from whoosh.index import open_dir from whoosh.query import compound, Term ix = open_dir("indexdir", indexname='article_index') with ix.searcher() as searcher: author_query = [Term('author', '黄河'), Term('author', '杜甫')] content_query = [Term('content', '黄河'), Term('content', '杜甫')] query = compound.Or([compound.Or(author_query), compound.Or(content_query)]) print(query) results = searcher.search(query) for data in results: print(data) 三个文档都会被搜索到, 如果你搜索的是一个句子,那么你可以使用analyzer 对整个句子进行分词,然后构造搜索条件,我所说的analyzer就是 analyzer = ChineseAnalyzer() 语句创建的对象。 3.4 分页搜索 如果搜索结果太多,那么你需要分页查询 results = searcher.search_page(query, 1) # 搜索第1页,默认每页10个结果 print(results.total) # 搜索到的文档总量,帮助你进行分页 你获取的是第一页的搜索结果,但results.total 会告诉你搜索结果一共有多少条,这样,你就知道该搜索多少页的数据了。
whoosh和jieba实现中文全文检索 截止目前(2018-8-5),Whoosh 项目已经整整一年没有更新(最后提交于 2017-07-16),作者可能已经弃坑。 简介 Whoosh 是一个纯 Python 实现的全文检索引擎,虽然不如 Elasticsearch,但好处是纯 Python 实现易于集成,在小项目中应用广泛。 Whoosh 自带的分词器不支持中文分词。jieba 是一个中文分词组件,实现了一个供 Whoosh 调用的中文分词器。两者结合使用即可以实现中文全文检索。 快速上手 环境准备 1 2 pip3 install jieba pip3 install whoosh 简单示例 输出结果: {'content': '这是我们增加的第一篇文档', 'title': '第一篇文档'} 第一篇<b class="match term0">文档</b> 0.5945348918918356 创建 Schema 使用 Whoosh 进行检索需要创建索引对象(index object),而索引对象的结构由 Schema 定义。 Schema 会列出索引对象的字段(field),字段是文档(document)中的一条信息,例如标题或者文本内容。字段可以通过参数,设置是否被搜索,是否在搜索结果中与被索引的字段一起返回。 类比 SQL 数据库表: Whoosh 索引 SQL 数据库表 Schema 表结构 field 字段 字段 field document 文档 记录 record 索引对象 整个表 举个例子: from whoosh.fields import TEXT, Schema from jieba.analyse import ChineseAnalyzer schema = Schema( title=TEXT(stored=True, analyzer=ChineseAnalyzer()), id=ID(stored=True), content=TEXT(stored=True), ) 上面的代码创建了一个 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 的索引使用文件存储,创建时传入目录名,索引文件就会存储在该目录下。 from whoosh.index import create_in, exists_in indexdir = "indexdir/" if not os.path.exists(indexdir): os.mkdir(indexdir) if not exists_in(indexdir): ix = create_in(indexdir, schema) exists_in 返回目录下是否存在索引,create_in 创建索引。如果在一个已经存在索引文件的目录下调用 create_in 创建索引,原索引会丢失。 exists_in 和 create_in 函数都可以传入 indexname 参数,指定创建的索引名称。 添加文档 有了索引对象后,就可以添加文档数据到索引中。 首先,获取索引对象: from whoosh.index import open_dir ix = index.open_dir(indexdir) open_dir 函数用于从指定目录中获取索引对象,该函数也可以传入 indexname 参数指定索引名称。 通过索引对象新建一个 IndexWriter 对象,该对象会锁住索引以进行写入,保证同时只有一个进程/线程进行写操作。 writer = ix.writer() 通过该 IndexWriter 对象的 add_document 方法添加 document,该方法接受关键字参数,与 Schema 定义保持一致。 writer.add_document( title="第一篇文档", path="/a", content="这是我们增加的第一篇文档" ) 所有 docment 添加完成后,调用 commit 方法写入索引。 writer.commit() 检索结果 首先通过索引对象创建一个 Searcher 对象,该对象使用完成后应该被关闭,可以使用 Python 中的 with 语法。 with ix.searcher() as searcher: # 查询操作 pass 可以直接使用 find 方法进行检索: with ix.searcher() as searcher: results = searcher.find("title", "文档") 或者先构造 QueryParser 对象,再使用 search 方法检索: from whoosh.qparser import QueryParser qp = QueryParser("content", schema=myindex.schema) q = qp.parse(u"hello world") with ix.searcher() as s: results = s.search(q) search 方法可以使用 limit 参数指定返回结果的个数: 1 results = s.search(q, limit=20) search_page 方法可以分页返回结果,默认每页 10 条结果,可以通过参数设置: # 每页20条结果,返回第 5 页的结果 results = s.search_page(q, 5, pagelen=20) 查询结果 results 对象类似 list,使用索引可以访问单个结果。 result = results[0] 单个结果的 score 属性可以得到对该 document 的权重评分,highlights 方法可以对指定 field 中的检索词进行高亮(加 b 标签)。 result.score result.highlights("title")
https://mrchi.cc/posts/7c3a9/
https://zhuanlan.zhihu.com/p/172348363
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。