(一)数据相关
1.1数据分类
可以将数据大致分为两种:结构化数据和非结构化数据。
结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。
非结构化数据:指不定长或无固定格式的数据,如邮件,word文档等磁盘上的文件。
1.2非结构化数据查询方法
关于非结构化数据查询方法,这里主要介绍两种:顺序扫描法与全文检索算法。
顺序扫描法(Serial Scanning)
比如要查找内容是包含某一字符串的文件,会查看所有文档,对于每一个文档,从头到尾进行比对,如果此文档包含此字符串,则该文档为我们要找的文件。接着看下一个文件,直到扫描完所有的文件,这种方式的查找方法使用的就是顺序扫描算法。比如平时我们使用的windows 搜索,只要搜索的文件存在一定会搜索到,只是速度相当慢。
全文检索(Full-text Search)
将非结构化数据中的一部分信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这部分从非结构化数据中提取出的然后重新组织的信息,称之索引。这种先建立索引,再对索引进行搜索的过程就叫全文检索。
(二)Lucene 登场
2.1Lucene 简介
Lucene 是一个基于 Java 的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能。Lucene 目前是 Apache 下的一个开源项目。也是目前最为流行的基于 Java 开源全文检索工具包。
Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能。
Lucene 采用的是一种称为反向索引(inverted index)的机制。反向索引就是说我们维护了一个词 / 短语表,对于这个表中的每个词 / 短语,都有一个链表描述了有哪些文档包含了这个词 / 短语。这样在用户输入查询条件的时候,就能非常快的得到搜索结果。
2.2Lucene 应用场景
- 互联网检索引擎。比如百度、Google 等。
- 站内全文检索引擎。比如淘宝、京东等。
2.3搜索流程和创建索引
获取原始内容的目的是为了创建索引,在索引前需要将原始内容创建成文档(Document),文档中包括一个一个的域(Field),域中存储内容。每个Document可以有多个Field,不同的Document 可以有不同的Field,同一个Document 可以有相同的Field(域名和域值都相同)。
将原始内容创建为包含域(Field)的文档(document),需要再对域中的内容进行分析,分析的过程是经过对原始文档提取单词、将字母转为小写、去除标点符号、去除停用词等过程生成最终的语汇单元,可以将语汇单元理解为简单的单词。
每个单词叫做一个Term,不同的域中拆分出来的相同的单词是不同的Term。Term中包含两部分:一部分是文档的域名,另一部分是单词的内容。
对所有文档分析得出的语汇单元进行索引,索引的目的是为了搜索,最终要实现只搜索被索引的语汇单元,从而找到对应Document(文档)。
对原始内容建立好索引后,就可以在这些索引上面进行搜索了。搜索引擎首先会对搜索的关键词进行解析,然后在建立好的索引库上面进行查找,最终返回和用户输入的关键词相关联的文档。
(三)Lucene 简单使用
3.1环境准备
这里我使用了Lucene 最新版本7.× 的jar 包,随着Lucene 版本的更新,其中一些类的使用方法也发生了变化,这里就不作具体介绍了。推荐一篇博文:从Lucene 4.10.3到Lucene 7.1.0:带你了解版本之间的些许差异,讲述了一些版本上的变化差异,有兴趣的话可以点击查看。
使用jar 包截图:
要搜索的文件:
Lucene 各个版本下载地址:http://archive.apache.org/dist/lucene/java/
使用jar 包下载地址:http://download.csdn.net/download/codejas/10272440
3.2代码实现
indexCreateTest()
方法创建索引
@Test
public void indexCreateTest() throws Exception{
List docList = new ArrayList<>();
File dir = new File("E:\\lucene\\test");
for(File file : dir.listFiles()){
String fileName = file.getName();
String fileCOntext= FileUtils.readFileToString(file);
Long fileSize = FileUtils.sizeOf(file);
Document doc = new Document();
TextField nameFiled = new TextField("fileName", fileName, Store.YES);
TextField cOntextFiled= new TextField("fileContext", fileContext, Store.YES);
TextField sizeFiled = new TextField("fileSize", fileSize.toString(), Store.YES);
doc.add(nameFiled);
doc.add(contextFiled);
doc.add(sizeFiled);
docList.add(doc);
}
File file = new File("E:\\lucene\\index");
FSDirectory directory = FSDirectory.open(file.toPath());
IndexWriterConfig cOnfig= new IndexWriterConfig();
IndexWriter indexWriter = new IndexWriter(directory, config);
for(Document doc : docList){
indexWriter.addDocument(doc);
}
indexWriter.commit();
indexWriter.close();
}
执行后,在本地磁盘的E:\lucene\index
目录下,会有一些文件,包含了索引和对应文档存储。
indexSearchTest()
方法查询索引
@Test
public void indexSearchTest() throws Exception{
Analyzer analyzer = new StandardAnalyzer();
QueryParser queryParser = new QueryParser("fileContext", analyzer);
Query query = queryParser.parse("fileName:java");
File file = new File("E:\\lucene\\index");
Directory dir = FSDirectory.open(file.toPath());
IndexReader indexReader = StandardDirectoryReader.open(dir);
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
TopDocs topdocs = indexSearcher.search(query, 5);
ScoreDoc[] scoreDocs = topdocs.scoreDocs;
System.out.println("=====count = " + topdocs.totalHits +"=====");
for(ScoreDoc scoreDoc : scoreDocs){
int docID = scoreDoc.doc;
Document document = indexReader.document(docID);
System.out.println("fileName:" + document.get("fileName"));
System.out.println("fileSize:" + document.get("fileSize"));
System.out.println("=====================================");
}
}
/** * 输出 * =====count = 3===== * fileName:Java GUC.txt * fileSize:1331 * ===================================== * fileName:Java NIO.txt * fileSize:1634 * ===================================== * fileName:Java 8.txt * fileSize:191 * ===================================== */
(四)总结
这篇博文主要介绍了Lucene 的一些相关的基本概念以及其创建索引与搜索过程,并通过一个简单的例子体会到了Lucene 的强大之处。希望这篇博文能够为学习 Lucene 的读者提供帮助。
参考博文:
https://www.ibm.com/developerworks/cn/java/j-lo-lucene1/index.html