示例实现"/>
1、介绍lucene的功能以及建立索引、搜索单词、搜索词语和搜索句子四个示例实现
Elasticsearch 系列文章
1、介绍lucene的功能以及建立索引、搜索单词、搜索词语和搜索句子四个示例实现
2、Elasticsearch7.6.1基本介绍、2种部署方式及验证、head插件安装、分词器安装及验证
3、Elasticsearch7.6.1信息搜索示例(索引操作、数据操作-添加、删除、导入等、数据搜索及分页)
4、Elasticsearch7.6.1 Java api操作ES(CRUD、两种分页方式、高亮显示)和Elasticsearch SQL详细示例
5、Elasticsearch7.6.1 filebeat介绍及收集kafka日志到es示例
6、Elasticsearch7.6.1、logstash、kibana介绍及综合示例(ELK、grok插件)
7、Elasticsearch7.6.1收集nginx日志及监测指标示例
8、Elasticsearch7.6.1收集mysql慢查询日志及监控
9、Elasticsearch7.6.1 ES与HDFS相互转存数据-ES-Hadoop
文章目录
- Elasticsearch 系列文章
- 一、Lucene全文检索库
- 1、全文检索
- 2、Lucene简介
- 二、示例
- 1、准备测试数据
- 2、建立索引库
- 3、实现
- 1)、maven 依赖
- 2)、java 实现
- 4、查询-单字搜索
- 1)、实现步骤
- 2)、代码
- 5、查询-词语搜索
- 1)、分词器与中文分词器
- 2)、实现步骤
- 3)、maven 依赖
- 4)、代码
- 5)、验证
- 6、句子搜索
- 4、倒排索引结构
本文简单的介绍了 lucene的功能以及四个示例(建立索引、搜索单词、搜索词语和搜索句子),是Elasticsearch的引导篇。
本文分为2个部分,即介绍lucene和使用示例。
一、Lucene全文检索库
1、全文检索
- 结构化数据与非结构化数据
结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等
非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等磁盘上的文件 - 搜索结构化数据和非结构化数据
使用SQL语言专门搜索结构化的数据
使用ES/Lucene/Solor建立倒排索引,根据关键字就可以搜索一些非结构化的数据 - 全文检索
全文检索是指通过一个程序扫描文本中的每一个单词,针对单词建立索引,并保存该单词在文本中的位置、以及出现的次数。用户查询时,通过之前建立好的索引来查询,将索引中单词对应的文本位置、出现的次数返回给用户,因为有了具体文本的位置,所以就可以将具体内容读取出来了,类似于通过字典中的检索字表查字的过程。
2、Lucene简介
Lucene是一种高性能的全文检索库,在2000年开源,最初由Doug Cutting(道格·卡丁)开发
Lucene是Apache的一个顶级开源项目,是一个全文检索引擎工具包。但Lucene不是一个完整的全文检索引擎,它只是提供一个基本的全文检索的架构,还提供了一些基本的文本分词库
Lucene是一个简单易用的工具包,可以方便的实现全文检索的功能
二、示例
通过搜索一个关键字就能够找到哪些文章包含了这些关键字。例如:搜索「hadoop」,就能找到hadoop相关的文章。
1、准备测试数据
自行准备测试数据即可
2、建立索引库
实现步骤
- 构建分词器(StandardAnalyzer)
- 构建文档写入器配置(IndexWriterConfig)
- 构建文档写入器(IndexWriter,注意:需要使用Paths来)
- 读取所有文件构建文档
- 文档中添加字段
- 写入文档
- 关闭写入器
3、实现
1)、maven 依赖
<!-- lucene核心类库 --><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>8.4.0</version></dependency><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-common</artifactId><version>8.4.0</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>
2)、java 实现
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;import org.apachemons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.FSDirectory;/*** 通过这个类来读取文章的文本文件,建立索引* * @author chenw**/
public class BuildArticleIndex {public static void main(String[] args) throws IOException {// 1. 构建分词器(StandardAnalyzer)Analyzer standardAnalyzer = new StandardAnalyzer();// 2. 构建文档写入器配置(IndexWriterConfig)IndexWriterConfig writerConfig = new IndexWriterConfig(standardAnalyzer);// 3. 构建文档写入器(IndexWriter,注意:需要使用Paths来)IndexWriter indexWriter = new IndexWriter(FSDirectory.open(Paths.get("D:\\workspace\\es\\lucene\\index")), writerConfig);// 4. 读取所有文件构建文档// 读取data目录中的所有文件File dataDir = new File("D:\\workspace\\es\\lucene\\data");File[] fileArray = dataDir.listFiles();// 迭代所有的文本文件,读取文件并建立索引for (File file : fileArray) {// 5. 文档中添加字段// 字段名 类型 说明// file_name TextFiled 文件名字段,需要在索引文档中保存文件名内容// content TextFiled 内容字段,只需要能被检索,但无需在文档中保存// path StoredFiled 路径字段,无需被检索,只需要在文档中保存即可// 在Lucene中都是以Document的形式来存储内容的// Lucene在添加文档的时候就会自动建立索引Document doc = new Document();// 如果需要建立索引,就用TextField,如果不需要就使用StoredFielddoc.add(new TextField("file_name", file.getName(), Field.Store.YES));doc.add(new TextField("content", FileUtils.readFileToString(file), Field.Store.NO));doc.add(new StoredField("path", file.getAbsolutePath()));// 6. 写入文档indexWriter.addDocument(doc);}// 7. 关闭写入器indexWriter.close();}
}
运行完上述程序后的输出如下图
4、查询-单字搜索
该示例只能搜索单字,如果想搜索多字,则需要使用相关分词器
1)、实现步骤
使用DirectoryReader.open构建索引读取器
构建索引查询器(IndexSearcher)
构建词条(Term)和词条查询(TermQuery)
执行查询,获取文档
遍历打印文档(可以使用IndexSearch.doc根据文档ID获取到文档)
关键索引读取器
2)、代码
import java.io.IOException;
import java.nio.file.Paths;import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;public class KeywordSearch {public static void main(String[] args) throws IOException {// 1. 使用DirectoryReader.open构建索引读取器DirectoryReader reader = DirectoryReader.open(FSDirectory.open(Paths.get("D:\\workspace\\es\\lucene\\index")));// 2. 构建索引查询器(IndexSearcher)// 用来搜索关键字的IndexSearcher indexSearcher = new IndexSearcher(reader);// 3. 构建词条(Term)和词条查询(TermQuery)TermQuery termQuery = new TermQuery(new Term("content", "他"));// 4. 执行查询,获取文档TopDocs topDocs = indexSearcher.search(termQuery, 50);// 5. 遍历打印文档(可以使用IndexSearch.doc根据文档ID获取到文档)ScoreDoc[] scoreDocArray = topDocs.scoreDocs;for (ScoreDoc scoreDoc : scoreDocArray) {// 在Lucene中,每一个文档都有一个唯一ID// 根据唯一ID就可以获取到文档Document document = indexSearcher.doc(scoreDoc.doc);// 获取文档中的字段System.out.println("-------------");System.out.println("文件名:" + document.get("file_name"));System.out.println("文件路径:" + document.get("path"));//content是否有内容,取决于创建索引时是否存储System.out.println("文件内容:" + document.get("content"));}// 6. 关闭索引读取器reader.close();}}运行结果
-------------
文件名:飞翔的精灵.txt
文件路径:D:\workspace\es\lucene\data\飞翔的精灵.txt
文件内容:null
-------------
文件名:一辈子陪伴.txt
文件路径:D:\workspace\es\lucene\data\一辈子陪伴.txt
文件内容:null
-------------
文件名:永远的坐票.txt
文件路径:D:\workspace\es\lucene\data\永远的坐票.txt
文件内容:null
-------------
文件名:大度也是一种美德.txt
文件路径:D:\workspace\es\lucene\data\大度也是一种美德.txt
文件内容:null
5、查询-词语搜索
1)、分词器与中文分词器
分词器是指将一段文本,分割成为一个个的词语的动作。例如:按照停用词进行分隔(的、地、啊、吧、标点符号等)。之前在代码中使用的分词器是Lucene中自带的分词器。这个分词器对中文很不友好,只是将一个一个字分出来,所以,就会从后出现上面的问题——无法搜索词语。
所以,基于该背景,我们需要使用跟适合中文的分词器。中文分词器也有不少,例如:
-
Jieba分词器
-
IK分词器
-
庖丁分词器
-
Smarkcn分词器
等等。此处使用比较好用的IK分词器来进行分词。 -
IK介绍
IK已经实现好了Lucene的分词器:
IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包。从2006年12月推出1.0版开始,IKAnalyzer已经推出了3个大版本。最初,它是以开源项目Luence为应用主体的,结合词典分词和文法分析算法的中文分词组件。新版本的 IKAnalyzer3.0则发展为面向Java的公用分词组件,独立于Lucene项目,同时提供了对Lucene的默认优化实现。 -
IKAnalyzer3.0特性
采用了特有的“正向迭代最细粒度切分算法“,支持细粒度和最大词长两种切分模式;具有83万字/秒(1600KB/S)的高速处理能力。
采用了多子处理器分析模式,支持:英文字母、数字、中文词汇等分词处理,兼容韩文、日文字符
优化的词典存储,更小的内存占用。支持用户词典扩展定义
针对Lucene全文检索优化的查询分析器IKQueryParser;引入简单搜索表达式,采用歧义分析算法优化查询关键字的搜索排列组合,能极大的提高Lucene检索的命中率。
2)、实现步骤
把之前生成的索引文件删除,然后将之前使用的StandardAnalyzer修改为IKAnalyzer。然后重新生成索引。
- 构建分词器(IKAnalyzer)
- 构建文档写入器配置(IndexWriterConfig)
- 构建文档写入器(IndexWriter,注意:需要使用Paths来)
- 读取所有文件构建文档
- 文档中添加字段
- 写入文档
- 关闭写入器
3)、maven 依赖
<!-- lucene核心类库 --><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId><version>8.4.0</version></dependency><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-common</artifactId><version>8.4.0</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency><dependency><groupId>com.jianggujin</groupId><artifactId>IKAnalyzer-lucene</artifactId><version>8.0.0</version></dependency>
4)、代码
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;import org.apachemons.io.FileUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;/*** 通过这个类来读取文章的文本文件,建立索引* * @author chenw**/
public class BuildArticleIndex {public static void main(String[] args) throws IOException {// 1. 构建分词器(StandardAnalyzer)Analyzer standardAnalyzer = new IKAnalyzer();// 2. 构建文档写入器配置(IndexWriterConfig)IndexWriterConfig writerConfig = new IndexWriterConfig(standardAnalyzer);// 3. 构建文档写入器(IndexWriter,注意:需要使用Paths来)IndexWriter indexWriter = new IndexWriter(FSDirectory.open(Paths.get("D:\\workspace\\es\\lucene\\index")), writerConfig);// 4. 读取所有文件构建文档// 读取data目录中的所有文件File dataDir = new File("D:\\workspace\\es\\lucene\\data");File[] fileArray = dataDir.listFiles();// 迭代所有的文本文件,读取文件并建立索引for (File file : fileArray) {// 5. 文档中添加字段// 字段名 类型 说明// file_name TextFiled 文件名字段,需要在索引文档中保存文件名内容// content TextFiled 内容字段,只需要能被检索,但无需在文档中保存// path StoredFiled 路径字段,无需被检索,只需要在文档中保存即可// 在Lucene中都是以Document的形式来存储内容的// Lucene在添加文档的时候就会自动建立索引Document doc = new Document();// 如果需要建立索引,就用TextField,如果不需要就使用StoredFielddoc.add(new TextField("file_name", file.getName(), Field.Store.YES));doc.add(new TextField("content", FileUtils.readFileToString(file), Field.Store.NO));doc.add(new StoredField("path", file.getAbsolutePath()));// 6. 写入文档indexWriter.addDocument(doc);}// 7. 关闭写入器indexWriter.close();}
}
5)、验证
采用单字搜索的例子,只是将搜索的字变成一个词语。运行结果如下:
-------------
文件名:永远的坐票.txt
文件路径:D:\workspace\es\lucene\data\永远的坐票.txt
文件内容:null
-------------
文件名:一辈子陪伴.txt
文件路径:D:\workspace\es\lucene\data\一辈子陪伴.txt
文件内容:null
6、句子搜索
要实现搜索句子,是将句子进行分词后,再进行搜索。我们需要使用QueryParser类来实现。通过QueryParser可以指定分词器对要搜索的句子进行分词。
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.wltea.analyzer.lucene.IKAnalyzer;import java.io.IOException;
import java.nio.file.Paths;
import java.text.ParseException;/*** @author chenw**/
public class SentenceSearch {public static void main(String[] args) throws IOException, ParseException, org.apache.lucene.queryparser.classic.ParseException {// 1. 构建索引读取器IndexReader indexReader = DirectoryReader.open(FSDirectory.open(Paths.get("D:\\workspace\\es\\lucene\\index")));// 2. 构建索引查询器IndexSearcher indexSearcher = new IndexSearcher(indexReader);// 3. 执行查询,获取文档QueryParser queryParser = new QueryParser("content", new IKAnalyzer());TopDocs topDocs = indexSearcher.search(queryParser.parse("人生是一条河"), 50);ScoreDoc[] scoreDocArrary = topDocs.scoreDocs;// 4. 遍历打印文档for (ScoreDoc scoreDoc : scoreDocArrary) {int docId = scoreDoc.doc;Document document = indexSearcher.doc(docId);System.out.println("文件名:" + document.get("file_name") + " 路径:" + document.get("path"));}indexReader.close();}}
运行结果:加载扩展词典:ext.dic
加载扩展停止词典:stopword.dic
文件名:月台.txt 路径:D:\workspace\es\lucene\data\月台.txt
文件名:永远的坐票.txt 路径:D:\workspace\es\lucene\data\永远的坐票.txt
文件名:大度也是一种美德.txt 路径:D:\workspace\es\lucene\data\大度也是一种美德.txt
文件名:一辈子陪伴.txt 路径:D:\workspace\es\lucene\data\一辈子陪伴.txt
文件名:飞翔的精灵.txt 路径:D:\workspace\es\lucene\data\飞翔的精灵.txt
4、倒排索引结构
倒排索引是一种建立索引的方法。是全文检索系统中常用的数据结构。通过倒排索引,就是根据单词快速获取包含这个单词的文档列表。倒排索引通常由两个部分组成:单词词典、文档。
以上,简单的介绍了 lucene的功能以及四个示例(建立索引、搜索单词、搜索词语和搜索句子)。
更多推荐
1、介绍lucene的功能以及建立索引、搜索单词、搜索词语和搜索句子四个示例实现
发布评论