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
文章目录
本文简单的介绍了 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.apache.commons.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,如果不需要就使用StoredField
doc.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的分词器:https://github.com/wks/ik-analyzer
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.apache.commons.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,如果不需要就使用StoredField
doc.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的功能以及四个示例(建立索引、搜索单词、搜索词语和搜索句子)。