您当前的位置:首页 > 计算机 > 编程开发 > Python

python全文搜索库Whoosh

时间:08-23来源:作者:点击数:

官方文档:https://whoosh.readthedocs.io/en/stable/

pypi:https://pypi.python.org/pypi/Whoosh/#downloads

安装

pip install Whoosh

Whoosh是一个纯python的全文搜索库

Whoosh官方文档介绍如下,

Whoosh is a library of classes and functions for indexing text and then searching the index. It allows you to develop custom search engines for your content. For example, if you were creating blogging software, you could use Whoosh to add a search function to allow users to search blog entries.

大意:Whoosh是索引文本及搜索文本的类和函数库。它能让你开发出一个个性化的经典搜索引擎。

例如,如果你在写博客选择(或者说博客搜索)程序,你可以用Whoosh添加一个让用户搜索博客条目的函数

因为做的是中文的全文检索需要导入jieba工具包以及whoosh工具包

Schema 有两个field, 标题title & 内容content

from whoosh.fields import Schema, TEXT
 
schema = Schema(title=TEXT, content=TEXT)

如果你不需要给任何field type传值,你可以只给类名 ,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的设计的更多信息

有了schema,你可以用create_in函数创建index

import os.path
from whoosh.index import create_in
 
if not os.path.exists("index"):
    os.mkdir("index")
ix = create_in("index", schema)

在底层,这将创建一个 Storage 对象来包含这个索引。一个Storage 对象 代表了索引将被存储在哪个媒介上。一般这将会是用来存储文件夹内一系列文件的索引FileStorage。

当你创建好索引后,你可以用open_dir打开它

from whoosh.index import open_dir
 
ix = open_dir("index")

IndexWriter对象

既然我们已经知道Index对象了,我们可以开始添加文档了。 Index对象的writer() 方法可以让你把文档加到索引上。 IndexWriter的add_document(**kwargs) 方法接受一个field name被映射到一个值的关键词参数:

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()

Searcher 对象

为了开始搜索Index,我们需要 一个 search 对象

searcher = ix.searcher()

你将经常想用一个with 语句打开searcher因为当你使用完毕时它会自动关闭。(searcher对象代表一系列打开的文件,所以你不明确的关掉他们,整个系统像蜗牛一样,你可能会用尽文件句柄):

with ix.searcher() as searcher:
    ...

当然这与下面的的代码等价:

try:
    searcher = ix.searcher()
    ...
finally:
    searcher.close()

Searcher的 search() 方法需要一个Query对象。你可以直接构造一个查询对象或者用一个查询分析器来分析每一个查询字符串。

例如,这个查询将会在内容field 中匹配同时包含  “apple” 和 “bear” 的文档:

# Construct query objects directly
from whoosh.query import *
myquery = And([Term("content", u"apple"), Term("content", "bear")])

你可以用一个在qparse模块中默认的分析器来分析一个查询字符串。 QueryParser的构造函数的第一个参数是默认要搜索的field。

这通常是 “body text” field,第二个可选参数是用来理解如何分析该field的schema:

# Parse a query string
from whoosh.qparser import QueryParser
parser = QueryParser("content", ix.schema)
myquery = parser.parse(querystring)

一旦你有一个Searcher 和一个 查询对象,你可以用 Search的 search方法来跑一个查询,并获取一个Results 对象:

>>> results = searcher.search(myquery)
>>> print(len(results))
1
>>> print(results[0])
{"title": "Second try", "path": "/b", "icon": "/icons/sheep.png"}

默认的  QueryParser 实现了一个与Lucene的查询语言很类似的语言。它让你用 AND 和 OR  将 terms 连接起来,用NOT 消除 terms,用括号将terms组成句子,做一些范围(range)、前缀(prefix)、通配符(wildcard)查询,明确搜索的不同field。默认情况下,经常与AND 合用(所以默认情况下, 你举出的所有terms 必须在文档中,以让文本匹配):

>>> 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")

# -*- coding:utf-8 -*-
import os,json
from whoosh.qparser import QueryParser
from whoosh.index import create_in,open_dir
from whoosh.sorting import FieldFacet
from whoosh.fields import *
from whoosh.filedb.filestore import FileStorage
from jieba.analyse import ChineseAnalyzer
from IPython.core.display import display, HTML


# 导入中文分词工具
analyzer = ChineseAnalyzer()
# 创建索引结构  stored为True表示能够被检索
schema = Schema(
    title=TEXT(stored=True, analyzer=analyzer),
    path=ID(stored=False),
    content=TEXT(stored=True, analyzer=analyzer),
    phone_name=TEXT(stored=True, analyzer=analyzer),
    price=NUMERIC(stored=True),
    phoneid=ID(stored=True)
)
# 存储schema信息至'indexdir'目录下
ix_path = 'indexdir/'
ix_name = 'test_index_name'
if not os.path.exists(ix_path):
    os.mkdir(ix_path)
# ---------------------------------创建索引-------------------------------------
# ix_path 为索引创建的地址,indexname为索引名称
ix = create_in(ix_path, schema=schema, indexname=ix_name)
writer = ix.writer()
writer.add_document(phone_name='name', price="price", phoneid="id")  # 此处为添加的内容
print("建立完成一个索引")
writer.commit()
# -----------------------------增加索引 -----------------------------------------
# 增加索引   操作索引的行为,类似读写文件,需要用完close,或者使用with语句。
storage = FileStorage(ix_path)  # idx_path 为索引路径
ix = storage.open_index(indexname=ix_name)
# 按照schema定义信息,增加需要建立索引的文档,注意:字符串格式需要为unicode格式
with ix.writer() as w:
    # from whoosh.writing import AsyncWriter
    # writer = AsyncWriter(ix,delay=0.25)
    w.add_document(title=u"第一篇文档", path=u"/a", content=u"这是我们增加,的第一篇文档")
    w.add_document(title=u"第二篇文档,呵呵", path=u"/b", content=u"这是我们增加的第二篇文档,哈哈")
    w.add_document(title=u"帅哥,呵呵", path=u"/b", content=u"帅哥,哈哈")
    # w.update_document()
    # w.delete_document()

# ix.close()
#---------------------------------检索展示-----------------------------------------------
with storage.open_index(indexname=ix_name).searcher() as searcher:
    # 检索标题中出现'文档'的文档
    results = searcher.find(u"content", u"文档")
    # 检索出来的第一个结果,数据格式为dict{'title':.., 'content':...}
    for r in results:
        display(HTML('<h3>' + r.get('title') + '</h3>'))
        display(HTML(r.highlights("content")))  # 高亮标题中的检索词
        print(r.score)  # 分数
        print(r.docnum)

        doc = r.fields()
        jsondoc = json.dumps(doc, ensure_ascii=False)
        display(jsondoc)  # 打印出检索出的文档全部内容

#--------------------------------------------------------------------------------
new_list = []
index = open_dir(dirname=ix_path, indexname=ix_name)  # 读取建立好的索引
with index.searcher() as searcher:
    parser = QueryParser("要搜索的项目,比如“phone_name", index.schema)
    myquery = parser.parse("搜索的关键字")
    facet = FieldFacet("price", reverse=True)  # 按序排列搜索结果
    # limit为搜索结果的限制,默认为10
    results = searcher.search(myquery, limit=None, sortedby=facet)
    for result1 in results:
        print(dict(result1))
        new_list.append(dict(result1))

Whoosh 有一些很有用的预定义 field types,你也可以很easy的创建你自己的。

  • whoosh.fields.ID
    这个类型简单地将field的值索引为一个独立单元(这意味着,他不被分成单独的单词)。这对于文件路径、URL、时间、类别等field很有益处。
  • whoosh.fields.STORED
    这个类型和文档存储在一起,但没有被索引。这个field type不可搜索。这对于你想在搜索结果中展示给用户的文档信息很有用。
  • whoosh.fields.KEYWORD
    这个类型针对于空格或逗号间隔的关键词设计。可索引可搜索(部分存储)。为减少空间,不支持短语搜索。
  • whoosh.fields.TEXT
    这个类型针对文档主体。存储文本及term的位置以允许短语搜索。
  • whoosh.fields.NUMERIC
    这个类型专为数字设计,你可以存储整数或浮点数。
  • whoosh.fields.BOOLEAN
    这个类型存储bool型
  • whoosh.fields.DATETIME
    这个类型为 datetime object而设计更多详细信息
  • whoosh.fields.NGRAM 和 whoosh.fields.NGRAMWORDS
    这些类型将fiel文本和单独的term分成N-grams(更多Indexing & Searching N-grams的信息)
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐