本帖最后由 王高飞 于 2018-12-5 13:37 编辑
Lucene&solr:维护数据,实现全文检索的
Lucene:solr底层
solr:服务器
一 什么是全文检索
数据分类:
结构化数据:有固定格式(数据类型)和有限的长度 比如:数据库表中的数据 元数据:关于数据的数据
查询: 使用SQL语句查询结构化数据 速度快
数据量大时 在数据库给某字段创建索引 但是索引不支持like(模糊)查询
只能做等值查询
解决模糊查询的问题 需要创建另外一套索引库:使用分词器
非结构化数据:没有固定格式(数据类型)也没有有限的长度 比如:word ppt excel pdf txt等磁盘上的文件
查询: 1 目测 顺序扫描 挨个硬找 比较慢
2 IO读取
3 全文检索:
全文检索:
对源数据创建索引+在索引上查询 电商项目
索引:
将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,
然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。
这部分从非结构化数据中提取出的然后重新组织的信息,我们称之索引。
二 全文检索的应用场景
1 搜索引擎: 谷歌 百度 搜狗 360
2 站内搜索: 淘宝 京东 微博 论坛
全文检索的数据不是直接来自数据库 而是来自通过数据库数据创建的索引库
三 怎么实现全文检索
使用Lucene实现
四 Lucene的简介
Lucene是apache下的一个开放源代码的全文检索引擎工具包。提供了完整的查询引擎和索引引擎,部分文本分析引擎。
Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。
目前我们使用核心core和分词器两个jar
五 Lucene实现全文检索的流程
1 创建索引
0 确定源文档:
要创建索引 使用全文检索的文件
1 获取源文档:
源文档是什么?
场景1:搜索引擎:指的是互联网上的所有网页
场景2:站内搜索:
1 磁盘上的文件
2 数据库表中的数据
获取源文档方式:
1 搜索引擎
使用网络爬虫(网络机器人)得到的 爬虫访问互联网上的每一个网页,将获取到的网页内容存储起来。
2 站内搜索:
1 磁盘上的文件:IO流
2 数据库表中的数据:sql查询
2 构建文档对象document
每个document中的属性可以不同 每个document都需要有唯一的id
一个Document对象放的内容是:
一个网页的内容(网络地址URL 网页标题 网页内容)
一个文件中内容(文件名 地址 大小 内容等)
表中的一条数据(一条数据每个列的内容 有多少列就应该创建多少个域)
3 分析文档,对内容分词
使用原始的分词
文件spring.txt内容:The Spring Framework provides a comprehensive programming and configuration model.
分词:为了创建索引库
1 按空格分词:按空格把语句划分成单词
2 处理大小写:忽略单词的大小写
3 处理停用词:去除停用词
4 标点符号:去除标点符号
分词后:
name:spring
content:spring
content:framework
content:provides
content:comprehensive
content:programming
content:configuration
content:model
4 创建索引(存储索引到索引库)
1 一个文档document可以有多个域 不同的文档可以有不同的域 同一个Document可以有相同的Field(域名和域值都相同)
2 域Field:域名+域值
域名 Filename
Content
size
path
域值 spring mvc l love you
3 term:不同的域中拆分出来的相同的单词是不同的term
域名+单词内容 Filename:spring
Content:love
Content:provides
Content:spring
4 对所有文档分析得出的语汇单元term进行索引
索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元从而找到Document(文档)。
5 创建索引是对语汇单元索引,通过词语找文档,这种索引的结构叫倒排索引结构。
倒排索引使得每个关键字索引对应多个文档ID,通过索引找到文档。
传统方法是正排索引,根据文档去搜索关键词,根据文件找到该文件的内容,在文件内容中匹配搜索关键字,这种方法是顺序扫描方法,数据量大、搜索慢。
2 查询索引:
查询索引也是搜索的过程。搜索就是用户输入关键字,从索引(index)中进行搜索的过程。
根据关键字搜索索引,根据索引找到对应的文档,从而找到要搜索的内容
1 用户查询接口 输入查询关键字的位置
2 创建查询
3 执行查询
4 渲染结果
六 Lucene入门案例
1 导入jar :lucene-core-4.10.3.jar、lucene-analyzers-common-4.10.3.jar commons-io.jar(读写本地文件)
2 创建索引:
第一步:创建一个java工程,并导入jar包。
第二步:创建一个indexwriter对象。
1 指定索引库的存放位置Directory对象
2 指定一个分析器Analyzer,对文档内容进行分析。
第二步:创建document对象。
第三步:创建field对象,设置域名 域值 是否分析 将field添加到document对象中。
第四步:使用indexwriter对象将document对象写入索引库,此过程进行索引创建。并将索引和document对象写入索引库。
第五步:关闭IndexWriter对象。
源码:
//指定索引存放位置
Directory directory=FSDirectory.open(new File("D:\Everday\Lucene&solr\Lucene&solr-day01\资料\index"));
//创建一个标准分析库 分词器
Analyzer analyzer=new StandardAnalyzer();
// //创建indexwriterCofig对象
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LATEST, analyzer);
////创建indexwriter对象
IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);
//原文档
File dir = new File("D:\Everday\Lucene&solr\Lucene&solr-day01\资料\上课用的查询资料searchsource");
//获得文件夹内的所有文件
File[] listFiles = dir.listFiles();
for (File f : listFiles) {
//文件名
String fileName = f.getName();
//文件内容
String fileContent = FileUtils.readFileToString(f);
//文件路径
String filePath = f.getPath();
//文件的大小
long fileSize = FileUtils.sizeOf(f);
//创建文件名域
//第一个参数:域的名称
//第二个参数:域的内容
//第三个参数:是否分析 索引 存储
Field fileNameField = new TextField("filename", fileName, Store.YES);
//文件内容域
Field fileContentField = new TextField("content", fileContent, Store.YES);
//文件路径域
Field filePathField = new StoredField("path", filePath);
//文件大小域
Field fileSizeField = new LongField("size", fileSize, Store.YES);
//创建document对象
Document document = new Document();
document.add(fileNameField);
document.add(fileContentField);
document.add(filePathField);
document.add(fileSizeField);
//创建索引,并写入索引库
indexWriter.addDocument(document);
}
//释放资源
indexWriter.close();
}
使用luke工具查看索引文件,运行bat文件 打开软件
2 查询索引
第一步:创建一个Directory对象,指定索引库存放的位置。
第二步:创建一个indexReader对象,需要指定Directory对象。
第三步:创建一个indexsearcher对象,需要指定IndexReader对象
第四步:创建一个TermQuery对象,指定查询的域和查询的关键词。
第五步:执行查询方法。
query:指定条件
n:查询数据量的限制
第六步:返回查询结果TopDocs。遍历查询结果并输出。
TopDocs:提供了获得结果的属性
topDocs.totalHits:匹配搜索条件的总记录数
topDocs.scoreDocs:顶部匹配记录
第七步:关闭IndexReader对象
源码:
//指定索引库存放的路径
Directory directory = FSDirectory.open(new File("D:\Everday\Lucene&solr\Lucene&solr-day01\资料\index"));
//创建indexReader对象
IndexReader indexReader = DirectoryReader.open(directory);
//创建indexsearcher对象
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//创建查询
Query query = new TermQuery(new Term("filename", "spring"));
//执行查询
//第一个参数是查询对象,第二个参数是查询结果返回的最大值
TopDocs topDocs = indexSearcher.search(query, 100);
//查询结果的总条数
System.out.println("查询结果的总条数:"+ topDocs.totalHits);
//遍历查询结果
//topDocs.scoreDocs存储了document对象的id
for (ScoreDoc scoreDoc : topDocs.scoreDocs) {
//scoreDoc.doc属性就是document对象的id
//根据document的id找到document对象
Document document = indexSearcher.doc(scoreDoc.doc);
System.out.println(document.get("filename"));
System.out.println(document.get("content"));
System.out.println(document.get("path"));
System.out.println(document.get("size"));
System.out.println("------------------------------------");
}
//关闭indexreader对象
indexReader.close();
}
八 分词器 分词器
apache自带的:中文分析效果不好
1 StandardAnalyzer:
单字分词:就是按照中文一个字一个字地进行分词。如:“我爱中国”,
效果:“我”、“爱”、“中”、“国”。
2 CJKAnalyzer
按两个字进行切分。如:“我是中国人”,效果:“我是”、“是中”、“中国”“国人”。
3 SmartChineseAnalyzer
导包 lucene-analyzers-smartcn-4.10.3.jar
对中文支持较好,但扩展性差,扩展词库,禁用词库和同义词库等不好处理
第三方提供的: 支持中文分析效果好
IKAnalyzer :
导入jar:IKAnalyzer2012FF_u1.jar
配置两个配置文件:stopword.dic和ext.dic 对中文分词效果较好 也可以自己指定禁用词和扩展词
九 分词器Analyzer的使用时机
1 创建索引时使用Analyzer
对于一些域值不需要分析器
1 不作为查询条件的内容,比如文件路径
2 不是匹配内容中的词而匹配Field的整体内容,比如订单号、身份证号等。
2 查询时也需要分词
注意:搜索使用的分析器要和索引使用的分析器一致。
|
|