Lucene:全文检索技术
概念:先创建索引,然后再对索引搜索的过程就是全文检索技术;
索引一次创建多次使用,表现为每次的查询速度很快。
索引:一个为了提高查询速度,创建某种数据结构的集合。
- 数据的分类:
- 结构化数据:格式、长度、数据类型固定
- 例如数据库的数据,
- 非结构化数据:格式、长度、数据类型不固定
- word文档、pdf文档等等
- 结构化数据:格式、长度、数据类型固定
- 数据的查询
- 结构化数据的查询:sql语句
- 简单、查询速度快
- 非结构化数据:查询某个关键字?
- 条件复杂,查询难度大
- 顺序扫描法
- 字符串匹配(顺序扫描)
- 使非结构化的数据变为结构化的数据便于查询
- 条件复杂,查询难度大
- 结构化数据的查询:sql语句
全文检索的应用场景
- 搜索引擎
- :百度、谷歌、搜索等等
- 站内搜索
- 论坛搜索,微博搜索,文章搜索
- 电商搜索
- jd,tb搜索
什么是Lucene:
Lucene是一个基于java开发全文检索工具包,提供了查询引擎和索引引擎
如何实现全文检索:
可以使用Lucene实现全文检索。Lucene是apache下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。
Lucene实现全文检索的流程:
配置开发环境
Lucene官网下载:
链接:https://pan.baidu.com/s/1IUfgnKP35NxZDxyGTbPEkw
提取码:3odb
luck
链接:https://pan.baidu.com/s/1loka5YFH7KHxzsG2lVDGfw
提取码:yd91
IKAnalyzer
链接:https://pan.baidu.com/s/1cCZktGtdAPV-rv9IRLm3Og
提取码:kisq
最低要jdk1.8
java工程和jar包
lucene-core
lucene-analyzers-common
commons-io
junit
入门案例:
步骤:
创建索引库
- 创建一个Directory对象,指定索引库保存的位置 Directory directory = FS 一般保存在磁盘上
- 基于Directory对象,创建一个IndexWriter对象 IndexWriter indexwrite = new IndexWriter(directory ,new IndexWirterConfig());
- 读取磁盘上的文件,对应每一个文件一个文档对象
- 向文档对象中添加域
- 把文档对象写入索引库
- 关闭IndexWriter对象
Directory directory = FSDirectory.open(new File("路径").toPath());//设定索引库存放位置
IndexWirter indexwriter = new IndexWirter(directory,new IndexWirterConfig());//索引写入对象,使用此对象来讲文档写入索引库
File dir = new File("路径"); //获取需要创建索引的文件的路径
File[] files = dir.listFiles();//获取此路径下所有的文件
for(File file:files){ //得到文件信息,建立并写入到域对象中去
//文件信息 此处获取的是文件的名字、路径、大小、内容信息
String fileName = file.getName();
String fileSize = FileUtils.sizeof(file);
String fileContent = FileUtils.readFileToString(file);
String filePath = file.getPath();
//创建域对象
Field fieldName = new TextField("name",fileName,Field.Store.YES);
Field fieldPath = new TextField("path",filePath,Field.Store.YES);
Field fieldSize = new TextField("size",fileSize,Field.Store.YES);
Field fieldContent = new TextField("content",fileContent,Field.Store.YES);
Document document = new Document();//创建文件对象 一个文件对应一个文档对象
//向文档对象里面添加域对象
document.add(fieldPath);
document.add(fieldSize);
document.add(fieldContent);
document.add(fieldName);
//使用索引写入对象将文档写入索引库
indexWirter.addDocument(document);
//释放资源
indexWirter.close();
}
使用Luke工具查询索引库:
上面使用的是Lucene是7.4.0版本的,若使用Luke工具的版本是和此对应的,就可以打开Lucene创建的索引库,需要注意的是此版本的Luke工具是JKD9编译的。
总的来说就是根据不同版本的Lucene而选择对应的Luke工具的版本,否则将打不开索引库。
当然创建索引库就是为了查询:下面给出查询步骤:
查询索引库
- 创建一个Directory对象,指定索引库的位置
- 创建一个IndexReader对象
- 创建一个IndexSearcher对象构造方法为IndexReader对象
- 创建一个Query对象,tremQuery创建,并且设置需要查询的域对象和查询的关键字
- 执行查询,得到一个TopDocs对象
- 取查询结果的总记录条数
- 取文档列表
Directory directory = FSDirectory.open(new File("路径").toPath());//获取到索引库的位置
IndexReader indexreader = DirectorReader.open(dirctor);//基于directory创建一个索引读取对象
IndexSeacher indexreacher = new IndexSeacher(indexreader);//基于索引读取对象获取索引查询对象
Query query = new TremQuery(new Term("title","Lucene"));//创建查询对象query,Query是一个抽象类,需要他的视线类TremQuery创建
TopDocs topdocs = indexSearcher.search(query,10);//使用indexSearcher对象进行查询,并且设置每次查询的数量
System.out.println("总记录数"+topdcs.totalHits(););//获取击中的所有数量总和
ScopeDoc[] ScopeDoc = topDocs.scoreDocs;//使用此方法scoreDocs可以获取到文档列表是一个数组,然后对数组进行查询
for(ScopeDoc doc:ScopeDoc){
int DocID = doc.doc;
Doucment document = indexSearcher.doc(docId);//获取文档ID
System.out.println(document.get("name"));
System.out.println(document.get("path"));
System.out.println(document.get("content"));
System.out.println(document.get("size"));
}
//释放资源
indexReader.close();
分析器的分析过程
标准分析器
默认使用标准分析器StandarAnalyzer 使用标准分析器,会将汉语关键字拆分为一个汉字一个汉字的形式
查看分析器的分析效果
使用Analyzer对象的tokenStream方法返回一个TokenStream对象,此对象中包含了最终的分词结果
步骤:
- 创建一个Analyzer对象,StandarAnalyzer对象
- 使用分析器对象的tokenStream方法获取TokenStream对象
- 向TokenStream对象设置一个引用,相当于一个指针
- 调用TokenStream对象的rest方法,如果不调用就抛异常
- 循环TokenStream对象
- 关闭TokenStream对象
Analyzer analyzer = new StandarAnalyzer();//使用一个标准分析器
TokenStream tokenstream = analyzer.tokenStream("xxxxx");//
CharTermAttribute charTermAttribute = tokenstream.addAttribute(CharTermAttribute.Class);
tokenstream.reset();
while(tokenstream.incrementToken()){
sout(charTermAttribute.ToString());
}
tokenStream.close();
中文分析器:
- jar包
- 配置文件和扩展词典
- 扩展词典禁止使用Windows的记事本打开,一定要保证文件的编码格式为utf-8
- 扩展词典:添加一点新词
- 停用词词典:无意义的词和敏感词汇
代码中使用:换一个IndexConfig的构造方法就行
new IndexWriterConfig(new IKAnalyzer())//使用IkAnalyzer中文分析器
索引库维护
每一个域的属性:是否索引、是否分析、是否存储
-
添加文档 :根据不同的数据类型来使用不同的域的类型去操作
//创建IndexWirter对象存入磁盘中并且设置中文解析器
IndexWrirter indexwirter = new IndexWriter(new FSDocument.open(new File("路径")),new IndexWirterCongif(new IKAnalyzer()));
//创建文档对象
Document document = new Document();
//文档中加入域对象
document.add(new Field("name","新的",Field.STORE.YES));
indexwriter.addDocument(document);
indexwriter.close();
删除文档
-
全部删除
IndexWriter.deleteAll();
IndexWriter.close();
查询删除 针对性的删除
IndexWriter.deleteDecutments(new Term("name","apache"));
IndexWriter.close();
修改文档:原理是先删除后添加
Document document = new Document();
document.add(new Field("name","新的",Field.STORE.YES));
//更新操作
indexwriter.updateDocument(new Field("name","原来的",document));
indexwriter.close();
索引库查询
Directory directory = FSDirectory.open(new File("路径").toPath());
IndexReader indexReader = new Indexreader(directory);
IndexSearcher indexSearcher = new IndexReader(indexreader);
Query query = new TermQuery(new Term("content","Lucene"));//使用TermQuery查询
TopDocs topDocs = indexSearcher.search(query,10);
ScoreDoc[] scoreDocs = topDocs.scorcDocs;
int sum = topDocs.titalHits;
for(ScoreDoc scoreDoc:scoreDocs){
int DocId = scoreDoc.doc;
Document document = new Document();//获取文档对象的ID 根据域名称拿到值
document = insearch.doc(DocId);
document.get("content");//获取
.....
}
indexSearcher.close();
indexReader.close();
RangeQuery:范围查询
Query query = LongPoint.newRangeQuery("size", 0l, 100l);//其他都一样
QueryPaser:根据查询内容先分词后查询
-
jar包
Directory directory = FSDirectory.open(new File("path").toPath());
IndexReader indexReader = new IndexReader(directory);
IndexSearcher indexSearcher = new IndexReacher(indexReader);
QueryParser queryParser = new QueryParser(Version.LUCENE_8_7_0,"name",new IkAnalyzer());//Lucene的版本 查询的域 解析器类型
TopDocs topDocs = indexSearcher.search(queryParser,10);
ScoreDoc[] scoreDocs = topDocs.scoreDoc;
int sum = topDocs.totalHits;
for(ScoreDoc scoreDoc:scoreDocs){
Doucument document = indexSearcher.doc(scoreDoc.doc);
document.get("content");//获取
.....
}
indexSearcher.close();
indexReader.close();