2. Lucene 实现全文检索的流程
2.1.索引和搜索流程图

绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:确定原始内容即要搜索的内容 -> 采集文档 -> 创建文档 -> 分析文档 ->索引文档
红色表示搜索过程,从索引库中搜索内容,搜索过程包括:用户通过搜索界面 -> 创建查询 -> 执行搜索,从索引库搜索 -> 渲染搜索结果
2.2.创建索引
步骤:

获得文档

原始文档:要基于那些数据来进行搜索,那么这些数据就是原始文档。
搜索引擎:使用爬虫获得原始文档
站内搜索:数据库中的数据。
案例:直接使用 io 流读取磁盘上的文件。
构建文档对象

对应每个原始文档创建一个 Document 对象
每个 document 对象中包含多个域(field)
域中保存的就是原始文档的数据
域的名称、域的值
每个文档都有一个唯一的编号,就是文档id。
注意:每个Document可以有多个Field,不同的Document可以有不同的Field,同一个Document可以有相同的Field(域名和域值都相同)

分析文档

就是分词的过程
根据空格进行字符串拆分,得到一个单词列表
把单词统一转换成小写。
去除标点符号。
去除停用词(无意义的词)
每个关键词都封装成一个 Term 对象中
Term 中包含两部分内容:
关键词所在的域
关键词本身
不同的域中拆分出来的相同的关键词是不同的 Term 。
创建索引

基于关键词列表创建一个索引。保存到索引库中。
索引库中:
索引
document 对象
关键词和文档的对应关系
通过词语找文档,这种索引的结构叫倒排索引结构。如下图:

倒排索引结构也叫反向索引结构,包括索引和文档两部分,索引即词汇表,它的规模较小,而文档集合较大。
2.3.查询索引
用户查询接口

用户输入查询条件的地方

例如:百度的搜索框

把关键词封装成一个查询对象(创建查询)

要查询的域
要搜索的关键词
执行查询

根据要查询的关键词到对应的域上进行搜索。
找到关键词,根据关键词找到 对应的文档
渲染结果

根据文档的 id 找到文档的对象
对关键词进行高亮显示
分页处理
最终展示给用户看。
3.入门程序
3.1.配置开发环境
Lucene 下载

Lucene是开发全文检索功能的工具包,从官方网站下载lucene-7.4.0,并解压。

官方网站:http://lucene.apache.org/
版本:lucene-7.4.0
Jdk要求:1.8以上
使用的jar包

​ lucene-core-7.4.0.jar

​ lucene-analyzers-common-7.4.0.jar

3.2.需求
实现一个文件的搜索功能,通过关键字搜索文件,凡是文件名或文件内容包括关键字的文件都需要找出来。还可以根据中文词语进行查询,并且需要支持多个条件查询。
本案例中的原始内容就是磁盘上的文件,如下图:

3.3.创建索引
实现步骤:

第一步:创建一个java工程,并导入jar包。
第二步:创建一个indexwriter对象。
​ 1)指定索引库的存放位置Directory对象
​ 2)指定一个IndexWriterConfig对象。
第二步:创建document对象。
第三步:创建field对象,将field添加到document对象中。
第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
第五步:关闭IndexWriter对象。

代码实现:

/**
* @Auther: lss
* @Date: 2019/5/7 17:27
* @Description:
*/
public class LuceneFirst {

@Test
public void createIndex() throws IOException {

// 创建一个 Directory 对象,指定索引库保存的位置
// 把索引库保存在内存中
// Directory directory = new RAMDirectory();
// 把索引库保存在磁盘中
Directory directory = FSDirectory.open(new File("D:\\IDEA1\\lelucene\\index").toPath());
// 基于 Directory 对象创建一个 IndexWriter 对象
IndexWriter writer = new IndexWriter(directory, new IndexWriterConfig());
// 读取磁盘上的文件,对应每个文件创建一个文档对象。
File dir = new File("D:\\searchsource");
File[] files = dir.listFiles();
for (File file : files) {
// 取文件名
String fileName = file.getName();
// 文件的路径
String filePath = file.getPath();
// 文件的路径
String fileContent = FileUtils.readFileToString(file, "utf-8");
// 文件的大小
long fileSize = FileUtils.sizeOf(file);
// 创建 Field

Field fieldName = new TextField("name", fileName, Field.Store.YES);
Field fieldPath = new TextField("path", filePath, Field.Store.YES);
Field fieldContent = new TextField("content", fileContent, Field.Store.YES);
Field fieldSize = new TextField("size", fileSize + "", Field.Store.YES);

// 创建文档对象
Document document = new Document();
// 向文档对象中添加域
document.add(fieldName);
document.add(fieldPath);
document.add(fieldContent);
document.add(fieldSize);
// 把文档对象写入索引库
writer.addDocument(document);
}
// 关闭 indexWriter 对象
writer.close();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
执行测试: 生成的索引库

这里生成的了一堆看不懂的文件,这些文件没办法用普通的文本编辑器查看,这该怎么办,有个小软件 luck 可以查看索引库。我会把文件上传到下载上。下载

使用 luke 查看索引库中的内容

我们使用的luke的版本是luke-7.4.0,跟lucene的版本对应的。可以打开7.4.0版本的lucene创建的索引库。需要注意的是此版本的Luke是jdk9编译的,所以要想运行此工具还需要jdk9才可以(PS:jdk 1.8貌似也是可以的)。

3.4.查询索引
实现步骤:

第一步:创建一个Directory对象,也就是索引库存放的位置。
第二步:创建一个indexReader对象,需要指定Directory对象。
第三步:创建一个indexsearcher对象,需要指定IndexReader对象
第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。
第五步:执行查询。
第六步:返回查询结果。遍历查询结果并输出。
第七步:关闭IndexReader对象

代码实现:

@Test
public void searchIndex() throws Exception {
// 创建一个 Directory 对象,指定索引库的位置
Directory directory = FSDirectory.open(new File("D:\\IDEA1\\lelucene\\index").toPath());
// 创建一个 IndexReader 对象
IndexReader indexReader = DirectoryReader.open(directory);
// 创建一个Indexsearcher 对象,构造方法中的参数 indexReader 对象。
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 创建一个 Query 对象,TermQuery
Query query = new TermQuery(new Term("name", "spring"));
// 执行查询,得到一个 TopDocs 对象
// 参数1:查询对象 参数2:查询结果返回的最大记录数
TopDocs topDocs = indexSearcher.search(query, 10);
// 取查询结果的总记录数
System.out.println("查询总记录数:" + topDocs.totalHits);
// 取文档列表
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
// 打印文档中的内容
for (ScoreDoc doc : scoreDocs) {
// 取文档 id
int docId = doc.doc;
// 根据 id 取文档对象
Document document = indexSearcher.doc(docId);
System.out.println(document.get("name"));
System.out.println(document.get("path"));
// System.out.println(document.get("content"));
System.out.println(document.get("size"));
System.out.println("------------------华丽的分割线");
}
// 关闭 IndexReader 对象
indexReader.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
执行测试:

这里没有打印内容,太多了不好截屏,同学们可以自行测试。

我们使用 luck 查看分词的结果,发现对于中文是不友好的,英文以按照单词分,而中文只能是一个字一个字的,

搜索英文是没有问题的,中文就不行了,单个字搜索还可以。这就有了问题,这就引入了一个分析器。

4.分析器
4.1.分析器的分词效果
代码实现:

@Test
public void testTokenStream() throws Exception {
// 创建一个标准分析器对象
Analyzer analyzer = new StandardAnalyzer();
// 获得tokenStream对象
// 第一个参数:域名,可以随便给一个
// 第二个参数:要分析的文本内容
TokenStream tokenStream = analyzer.tokenStream("", "The Spring Framework provides a comprehensive programming and configuration model.");
// TokenStream tokenStream = analyzer.tokenStream("", "单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”");
// 添加一个引用,可以获得每个关键词
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
// 添加一个偏移量的引用,记录了关键词的开始位置以及结束位置
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
// 将指针调整到列表的头部
tokenStream.reset();
// 遍历关键词列表,通过incrementToken方法判断列表是否结束
while (tokenStream.incrementToken()) {
// 关键词的起始位置
// System.out.println("start->" + offsetAttribute.startOffset());
// 取关键词
System.out.println(charTermAttribute);
// 结束位置
// System.out.println("end->" + offsetAttribute.endOffset());
}
// 关闭 tokenStream 对象
tokenStream.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
**执行测试:**英文

中文:

对中文不友好,这不行啊,我们查看源码发现 创建索引库我们没有指定分词器,使用的是默认的分词器 StandardAnalyzer

下面介绍中文分析器

4.2.中文分析器
4.2.1.Lucene 自带中文分词器
StandardAnalyzer:

单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。

SmartChineseAnalyzer:

对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理。

4.2.2.IKAnalyzer

使用方法:
​ 第一步:把jar包添加到工程中
​ 第二步:把配置文件和扩展词典和停用词词典添加到classpath下(hotword.dic 和 stopword.dic,配文件 IKAnalyzer.cfg.xml)

注意:hotword.dic和ext_stopword.dic文件的格式为UTF-8,注意是无BOM 的UTF-8 编码也就是说禁止使用windows记事本编辑扩展词典文件

使用EditPlus.exe保存为无BOM 的UTF-8 编码格式,如下图:

-**扩展词典:**添加一些新词

**停用词词典:**无意义的词或者是敏感词汇

4.3.使用自定义分析器
代码实现:

@Test
public void addDocument() throws Exception {
// 创建一个 IndexWriter 对象,需要使用 IKAnalyzer 作为分析器
Directory directory = FSDirectory.open(new File("D:\\IDEA1\\lelucene\\index").toPath());
// 创建一个 IndexWriter 对象,需要使用 IKAnalyzer 作为分析器
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new IKAnalyzer());
IndexWriter writer = new IndexWriter(directory, indexWriterConfig);
// 创建一个 document 对象
Document document = new Document();

// 向 document 对象添加域
document.add(new TextField("name", "新添加的文件", Field.Store.YES));
document.add(new TextField("content", "新添加的文件内容", Field.Store.NO));
document.add(new StoredField("path", "C:/temp/hello"));
// 把文档添写入索引库
writer.addDocument(document);
// 关闭索引库
writer.close();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

使用上面分词效果的代码测试:

以后我们在创建索引库时,使用 IKAnalyzer 就可以了。
---------------------

【Lucene】实现全文索引的更多相关文章

  1. 深度解析 Lucene 轻量级全文索引实现原理

    一.Lucene简介 1.1 Lucene是什么? Lucene是Apache基金会jakarta项目组的一个子项目: Lucene是一个开放源码的全文检索引擎工具包,提供了完整的查询引擎和索引引擎, ...

  2. Lucene就是这么简单

    什么是Lucene?? Lucene是apache软件基金会发布的一个开放源代码的全文检索引擎工具包,由资深全文检索专家Doug Cutting所撰写,它是一个全文检索引擎的架构,提供了完整的创建索引 ...

  3. Lucene原理之概念

    概念: 数据分两种: 1.结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等. 2.非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等.(半结构化数据:如XML,HTML等, ...

  4. Lucene Index Search

    转发自:  https://my.oschina.net/u/3777556/blog/1647031 什么是Lucene?? Lucene 是 apache 软件基金会发布的一个开放源代码的全文检索 ...

  5. NoSQL 35 个非主流数据库

    几乎每个Web开发人员都有自己喜欢的数据库,或自己最熟悉的数据库,但最常见的无外乎以下几种: MySQL PostgreSQL MSSQL SQLite MS Access 或是更简单的XML,文本文 ...

  6. Sql 调优总结

    1前言 Sql 语句调优对应用性能非常重要,看了几篇文章,总结了一下数据库优化的方法. 2 数据库 Sql 优化 1 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by ...

  7. Neo4j 3.5发布,在索引方面大幅增强

    Neo4j 3.5版本已正式发布,这也是Neo4j宣布企业版闭源以来发布的第一个版本. 这个版本在性能.资源使用率以及安全方面均有增强,我们可以先快速浏览一下这个版本: 全文索引 基于Index的快速 ...

  8. 全文索引-lucene,solr,nutch,hadoop之nutch与hadoop

    全文索引-lucene.solr.nutch,hadoop之lucene 全文索引-lucene.solr,nutch,hadoop之solr 我在去年的时候,就想把lucene,solr.nutch ...

  9. 全文索引Elasticsearch,Solr,Lucene

    最近项目组安排了一个任务,项目中用到了全文搜索,基于全文搜索 Solr,但是该 Solr 搜索云项目不稳定,经常查询不出来数据,需要手动全量同步,而且是其他团队在维护,依赖性太强,导致 Solr 服务 ...

  10. 5分钟了解lucene全文索引

    一.Lucene介绍及应用 Apache Lucene是当下最为流行的开源全文检索工具包,基于JAVA语言编写. 目前基于此工具包开源的搜索引擎,成熟且广为人知的有Solr和Elasticsearch ...

随机推荐

  1. Avoiding memory leaks

    Android applications are, at least on the T-Mobile G1, limited to 16 MB of heap. It's both a lot of ...

  2. 如何编写linux下nand flash驱动-1

    1.       硬件特性: [Flash的硬件实现机制] Flash全名叫做Flash Memory,属于非易失性存储设备(Non-volatile Memory Device),与此相对应的是易失 ...

  3. 洛谷P2679 子串——DP

    题目:https://www.luogu.org/problemnew/show/P2679 DP水题: 然而被摆了一道,下面加 // 的地方都是一开始没写好的地方...还是不周密: 仔细审题啊... ...

  4. Github个人主页不显示提交记录的问题

    最近发现自己连续三天在github上的提交没显示在个人主页上,一番搜索后终于发现原来是因为没有把git的配置改过来,提交的代码时使用了不同的email. https://code.bradymower ...

  5. Linux后门入侵检测工具,附bash漏洞解决方法

    一.rootkit简介 rootkit是Linux平台下最常见的一种木马后门工具,它主要通过替换系统文件来达到入侵和和隐蔽的目的,这种木马比普通木马后门更加危险和隐蔽,普通的检测工具和检查手段很难发现 ...

  6. E20180228-hm-xa

    bounds n. 界限; 界限; 出界; 在(某人允许进入的)界限以外; 出格的; 跳跃( bound的名词复数 ); (球等的) 反跳; indice  n. 指数(指指标, 如健康指数的指数); ...

  7. python 面向对象九 定制类

    一.定制类,实质就是我们自己重写特殊函数 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的. __slots__我们已经知道怎么用了,__l ...

  8. bzoj 4245: [ONTAK2015]OR-XOR【按位贪心】

    知道按位贪心但是不知道怎么贪-- 求一个a的异或前缀和s,然后按位从大到小贪心,ans的当前位能为0的条件是s中有>=m个位置这一位为0且没有flag,并且s[n]的这一位为0 如果符合要求,那 ...

  9. 洛谷P4114 Qtree1(树链剖分+线段树)

    传送门 LCT秒天秒地用什么树剖 这题可以算是树剖的比较裸的题目了 把每一条边的权值下放到他两边的点中深度较深的那个 然后直接用树剖+线段树带进去乱搞就可以了 //minamoto #include& ...

  10. Reshapeing operations

    Reshapeing operations Suppose we have the following tensor: t = torch.tensor([ [1,1,1,1], [2,2,2,2], ...