全文检索是什么?
全文搜索引擎:以下统称为全文检索
全文检索概念:从全文数据中进行检索就叫全文检索,是基于文本的搜索。
Apache Lucene是一个用Java写的高性能、可伸缩的全文检索引擎工具包,它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。Lucene的目标是为各种中小型应用程序加入全文检索功能。
现在比较流行的比较多的就是EltaticSearch[简称ES] ,它也是基于lucene扩展的全文检索工具
现实案例
- windows系统中的有搜索功能
2) 各大网站搜索引擎
了解一下:
结构化数据和非结构化数据
- 1.结构化数据:指具有“固定格式”或者“有限长度” 的数据,例如数据库 ,元数据等。
- 2.非结构化数据:指不定长或无固定格式的数据,例如邮箱,word文档。
- 3.半结构化数据:如xml,html等,当根据需要可按结构化数据来处理,也可抽取出纯文本按非结构化数据来处理。
我们为什么要用全文检索?
对以上几种案例从搜索类型,搜索范围,搜索速度进行分析。
常见搜索 | 搜索类型 | 搜索范围 | 搜索速度 |
Windows资源管理器 | 文件搜索 | 电脑上面文件 | 很慢 |
Eclipse帮助文档搜索 | 全文索引搜索 | 帮助文档 | 快 |
数据库搜索 | 数据库搜索 | 数据库表 | 慢 |
互联网搜索 | 全文索引搜索 | 互联网资源 | 很快 |
综上所述:
对一个非结构化的文本数据进行搜索效率很低,可以使用全文检索(全文索引搜索),就是使用一定的技术(在这里我们使用lucene)将非结构化的文本转换为有一定的结构,提高文本的检索效率。
不仅如此:全文检索还有以下特点
- 相关度排序:最高的排在最前面,官网中相关的网页排在最前面;
- 对摘要进行了截取;
- 关键词的高亮。
- 只关注文本,不考虑语义。
- 快
比如在输入框中输入“中国的首都在哪里”,搜索引擎不会以对话的形式告诉你“在北京”,而仅仅是列出包含了搜索关键字的网页。
在搜索引擎中查询关键词或句子时,你在最后加上问号也是没有意义的做法,会直接被过滤掉。
一般在什么时候使用
1.替换数据库模糊查询,提高查询速度(接触最多)
- 数据库缺点
1.查询速度慢
2.模糊查询搜索效果不佳
3.没有相关度排序 - 具体
关系数据库中进行模糊查询时,数据库自带的全文索引将不起作用,此时需要通过全文检索来提高速度。
2.只对“指定领域”的网站进行索引与搜索(即垂直搜索)
如“818工作搜索”、“有道购物搜索”
3.在word、pdf等各种各样的数据格式中检索内容
4.其它场合:比如搜狐拼音输入法、Google输入法等
项目中我们使用Lucene替换数据库中的like模糊查询。Like模糊查询通过explain解释没有使用到索引,会对全表进行逐行的扫描,如果说数据量比较庞大,搜索效率极低,用户体验差并且数据库压力大。
我们使用Lucene替换数据库的模糊查询,提高查询速度,增强用户体验,降低数据库的压力。
底层原理:[创建索引],[根据索引查询]
- 创建索引
步骤:
- 1 把文本内容转换为Document对象文本是作为Document对象的一个字段而存在
- 2 准备IndexWriter(索引写入器)
- 3 通过IndexWriter,把Document添加到缓冲区并提交
addDocument();
commit();
close();
//创建索引的数据 现在写死,以后根据实际应用场景
String doc1 = "hello world";
String doc2 = "hello java world";
String doc3 = "hello lucene world";
private String path ="F:/eclipse/workspace/lucene/index/
hello";
@Test
public void testCreate() {
try {
//2、准备IndexWriter(索引写入器)
//索引库的位置 FS fileSystem
Directory d = FSDirectory.open(Paths.get(path ));
//分词器
Analyzer analyzer = new SimpleAnalyzer();
//索引写入器的配置对象
IndexWriterConfig conf = new IndexWriterConfig(analyzer);
IndexWriter indexWriter = new IndexWriter(d, conf);
System.out.println(indexWriter);
//1、 把文本内容转换为Document对象
//把文本转换为document对象
Document document1 = new Document();
//标题字段
document1.add(new TextField("title", "doc1", Store.YES));
document1.add(new TextField("content", doc1, Store.YES));
//添加document到缓冲区
indexWriter.addDocument(document1);
Document document2 = new Document();
//标题字段
document2.add(new TextField("title", "doc2", Store.YES));
document2.add(new TextField("content", doc2, Store.YES));
//添加document到缓冲区
indexWriter.addDocument(document2);
Document document3 = new Document();
//标题字段
document3.add(new TextField("title", "doc3", Store.YES));
document3.add(new TextField("content", doc3, Store.YES));
//3 、通过IndexWriter,把Document添加到缓冲区并提交
//添加document到缓冲区
indexWriter.addDocument(document3);
indexWriter.commit();
indexWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
- 根据索引搜索
步骤
- 1 封装查询提交为查询对象
- 2 准备IndexSearcher
- 3 使用IndexSearcher传入查询对象做查询-----查询出来只是文档编号DocID
- 4 通过IndexSearcher传入DocID获取文档
- 5 把文档转换为前台需要的对象 Docment----> Article
@Test
public void testSearch() {
String keyWord = "lucene";
try {
// * 1 封装查询提交为查询对象
//通过查询解析器解析一个字符串为查询对象
String f = "content"; //查询的默认字段名,
Analyzer a = new SimpleAnalyzer();//查询关键字要分词,所有需要分词器
QueryParser parser = new QueryParser(f, a);
Query query = parser.parse("content:"+keyWord);
// * 2 准备IndexSearcher
Directory d = FSDirectory.open(Paths.get(path ));
IndexReader r = DirectoryReader.open(d);
IndexSearcher searcher = new IndexSearcher(r);
// * 3 使用IndexSearcher传入查询对象做查询-----查询出来只是文档编号DocID
TopDocs topDocs = searcher.search(query, 1000);//查询ton条记录 前多少条记录
System.out.println("总命中数:"+topDocs.totalHits);
ScoreDoc[] scoreDocs = topDocs.scoreDocs;//命中的所有的文档的封装(docId)
// * 4 通过IndexSearcher传入DocID获取文档
for (ScoreDoc scoreDoc : scoreDocs) {
int docId = scoreDoc.doc;
Document document = searcher.doc(docId);
// * 5 把文档转换为前台需要的对象 Docment----> Article
System.out.println("=======================================");
System.out.println("title:"+document.get("title")
+",content:"+document.get("content"));
}
} catch (Exception e) {
e.printStackTrace();
}
}