Lucene基本概念及使用
Posted 程序员食堂
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lucene基本概念及使用相关的知识,希望对你有一定的参考价值。
新卓越前端/Java暑期班火热开启,给自己一个拿年薪20w的机会
西安邮电大学长安校区
Tel:151-9186-5006
地点:西区图书馆A104
西安科技大学临潼校区
Tel:158-9142-6016
地点:旧图书馆后门信息网络中心一楼
1. 搜索引擎组件
1.1
索引组件
为了快速搜索大量的文本,必须针对文本建立索引,将文本内容转换成能够进行快速搜索的格式。
这个过程就叫做索引操作(indexing),输出就是索引(index)
1.1.2 建立文档
获取原始内容之后,就需要对内容进行索引,首先必须将内容转换成文档,以供搜索引擎使用。
文档主要包括几个带值的域,比如标题、正文、摘要、作者和链接(URL)。
然后需要将原始内容中的文本提取出来写入各个文档。
1.1.3 文档分析
搜索引擎不能直接对文本进行索引,而必须将文本分割成一系列被称为 词汇单元 的独立原子元素。
这一步骤决定文档中的文本域如何分割成 词汇单元 系列。
Lucene 提供了大量内嵌的分析器能够轻松完成这步操作
1.1.4 文档索引
在本步骤中,文档将被加入到索引列表。
1.2
搜索组件
搜索处理过程就是从索引中查找单词,从而找到包含该单词的文档。
1.2.1 建立查询
搜索请求会被转换成搜索引擎使用的 查询(query) 对象格式。
查询对象可能很简单,也可能很复杂。 Lucene 提供了一个称之为 查询解析器(QueryParser) 的强大开发包,用它可以根据通用查询语法将用户输入的文本处理成查询对象。
查询语句可以包含 布尔运算、短语查询或通配符查询。
1.2.2 搜索查询
查询检索索引并返回与查询语句匹配的文档,结果返回时按照查询请求来排序
常见的搜索理论模型:
1.纯布尔模型:文档不管是否匹配查询请求,都不会被评分,匹配文档与评分不相关,一条查询仅获取所有匹配文档集合的一个子集。
2.向量空间模型:查询语句和文档都是高维空间的向量模型,这里每一个独立的项都是一个维度,查询语句和文档之间的相关性或相似性由各个向量之间的距离计算得到。
3.概率模型:采用全概率的方法来计算文档和查询语句匹配的概率。
Lucene 采用了 空间向量模型和纯布尔模型
2. 核心技术
Lucene 是一个全文搜索框架
● 倒排索引
● 压缩算法
● 二元搜索
2.1
倒排索引
● 单词——文档矩阵
3. Lucene
的工作方法
Lucene 提供的服务实际包含两部分,一入一出:
入就是写入,将提供的源(本质上是字符串)写入索引或者将其从索引中删除;
出就是读取,向用户提供全文搜索服务,让用户可以通过关键词定位源。
● 写入:源字符首先经过 analyzer 处理,包括:分词,拆分成一个个单词;去除 stopword 。将源中需要的信息加入 Document 的各个 Field 中,并把需要索引的 Field 索引起来,把需要存储的 Field 存储起来。
● 读取:用户提供关键词,经过 analyzer 处理,对处理后的关键词搜索索引,找出对应的 Document。用户根据需要从找到的 Document 中提取出需要的 Field。
document:用户提供的源是一条条记录,它们可以是文本文件、字符串或者数据库表的一条记录等等。一条记录经过索引之后,就是以一个 Document 的形式存储在索引文件中的。用户进行搜索,也是以 Document 列表的形式返回。
field:一个 Document 可以包含多个信息域,例如一篇文章可以包括标题、正文、最后修改时间等信息域,这些信息域是通过 Field 在 Document 中存储的。
Field 有两个属性可选:存储和索引。通过存储属性,可以控制是否对这个 Field 进行索引。
——张嘉佳《从你的全世界路过》
4. 示例代码
4.1
4.1 导入依赖
<!-- lucene -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>5.5.4</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queries</artifactId>
<version>5.5.4</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>5.5.4</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>5.5.4</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<version>5.5.4</version>
</dependency>
<!-- apache-common -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
4.2
环境准备
准备 index 和 data 两个目录,分别用于存放索引和文档
● data 随便从其他项目中复制了几个 LICENSE
● index 保持为空,当 Lucene 运行的时候会自动进行创建
4.3
创建索引
public class CreateIndex {
/*
* 索引目录
*/
public static final String INDEX_DIR = "/Users/destiny/IdeaProjects/lucene-demo/src/main/resources/index";
/*
* 文本目录
*/
public static final String DATA_DIR = "/Users/destiny/IdeaProjects/lucene-demo/src/main/resources/data";
public void createIndex() throws IOException {
// 目录对象,描述了索引的存放位置,需要由 Path 进行初始化
Directory directory = FSDirectory.open(Paths.get(INDEX_DIR));
// 创建分词器
Analyzer analyzer = new StandardAnalyzer(); // 由分词器对 IndexWriterConfig 进行初始化
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
File file = new File(DATA_DIR);
File[ ] files = file.listFiles();
if (files != null) {
// 读取并遍历文本路径下的所有文件,用于生成文档及其索引
for (File f : files) {
// 创建文档
Document document = new Document(); // 为文档设置 Field
document.add(new StringField("filename", f.getName(), Field.Store.YES));
document.add(new TextField("content", FileUtils.readFileToString(f, Charset.defaultCharset()), Field.Store.YES));
document.add(new LongField("lastModify", f.lastModified(), Field.Store.YES));
// 写入索引
indexWriter.addDocument(document);
}
}
indexWriter.close();
}
public static void main(String[ ] args) throws IOException {
CreateIndex createIndex = new CreateIndex();
createIndex.createIndex();
}
}
运行完毕之后,发现 index 路径下多了一些文件,即为文档的索引。
4.4
查询索引
public class SearchIndex {
public void search() throws IOException, ParseException {
// 打开索引所在路径
Directory directory = FSDirectory.open(Paths.get(CreateIndex.INDEX_DIR));
IndexReader indexReader = DirectoryReader.open(directory);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
QueryParser queryParser = new QueryParser("content", new StandardAnalyzer());
Query query = queryParser.parse("from");
// 找到符合条件的前 10 条 Document 的索引的集合
TopDocs search = indexSearcher.search(query, 10);
// 遍历集合并打印文件名称
for (ScoreDoc scoreDoc : search.scoreDocs) {
int docId = scoreDoc.doc;
Document document = indexReader.document(docId);
String filename = document.get("filename");
System.out.println("filename: " + filename);
}
}
public static void main(String[] args) throws IOException, ParseException {
SearchIndex searchIndex = new SearchIndex();
searchIndex.search();
}
}
查询结果:
5. 理解索引
过程核心类
执行简单的索引过程需要用到以下几个类:
● IndexWriter
● Directory
● Analyzer
● Document
● Field
5.1
IndexWriter
IndexWriter(写索引)是索引过程的核心组件,这个类负责创建新索引或者打开已有索引,以及向索引中添加、删除或者是更新被索引文档的信息。为开发者提供针对索引文件的写入操作,但不能用于读取或者搜索索引。IndexWriter 需要开辟一定的空间用来存储索引,该功能可以由 Directory 完成。
5.2
Directory
Directory 描述了 Lucene 索引存放的位置。它是一个抽象类,其实现类负责具体指定索引的存储路径。在上面的例子中,我们使用 FSDirectory.open() 方法来获取真实文件在文件系统中的存储路径,然后将她们依次传递给 IndexWriter 类的构造方法。
IndexWriter 不能直接索引文本,需要先由 Analyzer 将文本分割成独立的单词才行。
5.3
Analyzer
文本文件在被索引之前,需要经过 Analyzer 处理,Analyzer 由 IndexWriter 的构造方法来指定,负责从被索引文本文件中提取词汇单元,并剔除剩下的无用信息。如果被索引的内容不是纯文本文件,那就需要先将其转换成文本文档。
Analyzer 是一个抽象类,其实现类中:
● 有的用于跳过停用词(指一些常用且不能帮 助区分文档的词,如a、an、the、in 和 on 等)
● 有的用于把词汇转换成小写,以使得搜索过程不区分大小写
● 等等
分析器的分析对象为文档。
5.4
Document
Document 代表一些 域(Field) 的集合,可以将 Document 理解为虚拟文档,如 Web页面、邮件信息等。文档的域代表文档或者文档相关的一些元数据。
Lucene 只处理文本和数字,Lucene 的内核本身只处理 java.lang.String 和 java.io.Reader 对象和本地数字类型
Document 对象的结构比较简单,为一个多个 Field 对象的容器, Field 是指包含能被索引的文本内容的类。
5.5
Field
索引中,每个文档都包含一个或者多个不同命名的域,这些域包含在 Field 类中。
每个域都有一个域名和对应的值,以及一组选项来精确控制 Lucene 索引操作各个域值。
6. 理解搜索
过程核心类
核心类:
● IndexSearcher
● Term
● Query
● TermQuery
● TocDocs
6.1
IndexSearcher
用于搜索 IndexWriter 所创建的索引,可以将它看做一个以只读方式打开索引的类。
它需要利用 Directory 实例来掌握前期创建的索引,然后才能提供大量的搜索方法,最简单的搜索方法是将单个 Query 对象和 int topN 所谓该方法的参数,返回一个 TopDocs 对象。
6.2
Term
Term 是搜索功能的基本单元,与 Field 对象类似,Term 对象包含一对字符串元素:域名和单词,注意 Term 对象还与索引操作有关。
6.3
Query
Lucene 含有许多具体的 Query 子类
6.4
TermQuery
是 Lucene 提供的最基本的查询类型,也是简单的查询类型之一,它用来匹配指定域中包含特定值的文档。
6.5
TopDocs
TopDocs 类是一个简单的容器指针,指针一般指向前 N 个排名的搜索结果,搜索结果即匹配查询条件的文档。TopDocs 会记录前 N 个结果中每个结果的 int docID 和浮点型分数。
以上是关于Lucene基本概念及使用的主要内容,如果未能解决你的问题,请参考以下文章
C++11多线程第一篇:并发基本概念及实现,进程线程基本概念