Lucene是用于全文检索的开源库,Apache软件基金会提供支持。它由Java语言开发,也提供Python接口调用。
本文介绍使用开源项目Lupyne构建垂直搜索引擎,搜索本地网页中的内容。它使用Python语言编写,搜索功能用Lucene引擎实现,使用html2text从本地网页中提取数据,实现对网页中文本的搜索,前端调用CherryPy框架(flask的web server常用作开发测试。而cherrypy的web server常用于生产环境),提供网页搜索功能。
运行文中实例需要匹配Java,Python,Lucene等各个软件版本,环境配置比较复杂,因而基于Lucene提供的docker image环境构建。
Lucene元素
使用Lucene之前,先来了解一些相关概念。
Directory:指定如何保存构建的索引,测试时常保存在内存中,实际应用中,一般将其保存在文件系统中,本例将索引保存在/tmp/a目录下。
Analyzer:分析器,用于处理文本,如分词,去停用词等。
IndexWriter:对索引进行增删查改的工具,一般的操作都围绕IndexWriter展开。
Document:构造搜索的基本单位,一般是网页、文档、邮件等。
Field:一个Document可能包含多个域Field,比如标题、正文、作者等。
实例
下面介绍垂直搜索引擎的具体构建方法。
下载Lupyne源码
$ git clone [https://github.com/coady/lupyne](https://github.com/coady/lupyne)
下载docker镜像(在Linux系统中运行) $ docker pull coady/pylucene # 约2.52G
运行镜像
$ docker run --rm -v /exports:/exports --net=host -it coady/pylucene bash
启动docker时使用了--net=host,使docker内外使用相同端口号访问,-v将宿主机目录映射到镜像内部目录。
在镜像内安装支持软件
$ cd /exports/xxx # 切换到lupyne源码所在目录
$ python setup.py install
$ pip install cherrypy
$ pip install pytest
$ pip install clients
$ pip install jupyter # 供进一步开发使用
$ pip install html2text # 解析html内容
运行jupyter开发环境:
$ jupyter notebook --allow-root -y --no-browser --ip=0.0.0.0
在docker之外的浏览器中访问示例文件:http://localhost:8888/notebooks/docs/examples.ipynb,其中对比使用lupyne封装与直接使用pylucene分别建立索引、查询、检索、排序和分组的不同代码,可直接运行。
读取目录下的网页内容,写入索引数据:
import lucene
from lupyne import engine
from org.apache.lucene import analysis, document, index, queryparser, search, store
import os
import html2text
def parse_html(root_dir, path, indexer, debug=False):
f = open(path,"r")
content = f.read()
text = html2text.html2text(content)
strings = [i for i in text.split("\n") if len(i) > 0]
for i in strings:
if debug:
print(len(strings), "insert", i)
path = path.replace(root_dir, "http://localhost:8080/")
indexer.add(content=i, path=path)
indexer.commit()
def insert_dir(root_dir, book_dir):
html_dir = os.path.join(root_dir, book_dir)
for root, dirs, files in os.walk(html_dir):
for f in files:
if f.endswith("html") or f.endswith("htm"):
path = os.path.join(root, f)
print(path)
parse_html(root_dir, path, indexer)
def search(keyword):
hits = indexer.search(keyword, field='content')
for hit in hits:
print(hit)
if __name__ == '__main__':
BOOK_ROOTDIR = '/exports/books/contents/' # 数据根目录,与Lucene中配置文件一致
assert lucene.getVMEnv() or lucene.initVM()
indexer = engine.Indexer(directory="/tmp/a/") # 数据存储目录
indexer.set('content', engine.Field.Text, stored=True)
indexer.set('path', engine.Field.Text, stored=True)
# 插入
insert_dir(BOOK_ROOTDIR, '知识图谱/text')
# 搜索
search('Lucene')
indexer.close()
设置Lupyne的配置文件:
[global]
tools.staticdir.on=True
tools.staticdir.dir='/exports/books/contents/'
tools.staticdir.section=''
启动Lupyne服务
$ python -m lupyne.server /tmp/a -c a.cfg
搜索:在浏览器打开 http://localhost:8080/search?q=content:lucene 如只取前三个使用: http://localhost:8080/search?q=content:lucene&count=3
打开被搜索网页: http://localhost:8080/知识图谱/text/part0013_split_006.html
此时,就实现了搜索本地网页的最简版本垂直搜索引擎,尽管网页还比较简陋。
扩展
Elasticsearch (ES)是一个开源的搜索引擎,建立在Lucene基础之上。 Lucene可能是目前存在的,不论开源还是私有的,拥有最先进,高性能和全功能搜索引擎功能的库。但是 Lucene 仅仅只是一个库,相对来说ES+Kibana更像是一套相对成熟的方案。它提供Web服务,客户端可通过Http请求或者API接口增删查改,它相对于Lupyne更复杂,功能也更多。当然无论使用何种底层库,都需要自己解释和插入数据。