Lucene
一,Lucene简介
1.Lucene是什么?
Lucene是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构。
Lucene提供了完整的查询引擎和索引引擎,部分文本分析引擎。说到底它是一个信息检索程序库,而不是应用产品。
因此它并不像百度或者google那样,拿来就能用,它只是提供了一种工具让你能实现这些产品。
2.Lucene能做什么?
要回答这个问题,先要了解lucene的本质。实际上lucene的功能很单一,说到底,就是我们给它若干个字符串,然后它为我们提供一个全文搜索服务,最后告诉我们要搜索的关键词出现在哪里。
知道了这个本质,我们就可以发挥想象做任何符合这个条件的事情了。比如我们可以把站内新闻都索引了,做个资料库;也可以把一个数据库表的若干个字段索引起来,那就不用再担心因为“%like%”而锁表了;学完lucene,你也可以写个自己的搜索引擎了……
3.Lucene速度测试
测试一:250万记录,300M左右文本,生成索引380M左右,800线程下平均处理时间300ms。
测试二:37000记录,索引数据库中的两个varchar字段,索引文件2.6M,800线程下平均处理时间1.5ms。
二,学习Lucene
1.为什么lucene这么快?
倒排索引, 压缩算法, 二元搜索
2.倒排序索引
它是根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。
由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(invertedindex)。
3.二元搜索
比如它可能根据关键词的字典顺序去排序,这样我们在查找时,可以采用分段的查找,类似与数组排序中的二分法查找(前提是数组是排序好的,无论是正序还是倒叙)
4.工作方式
Lucene提供的服务实际包含两部分:一入一出。
所谓入是写入,即将你提供的源(本质是字符串)写入索引或者将其从索引中删除;
所谓出是读出,即向用户提供全文搜索服务,让用户可以通过关键词定位源。
5.写入流程
1、源字符串首先经过analyzer处理,包括:分词,分成一个个单词;去除stopword(可选)。
2、将源中需要的信息加入Document的各个Field(信息域)中,并把需要索引的Field索引起来,把需要存储的Field存储起来。
3、将索引写入磁盘。
6.读出流程
1、用户提供搜索关键词,经过analyzer处理。
2、对处理后的关键词搜索它的索引,找出对应的Document。
3、用户根据需要从找到的Document中提取需要的Field。
7.Document
用户提供的源是一条条记录,它们可以是文本文件、字符串或者数据库表的一条记录等等。一条记录经过索引之后,就是以一个Document的形式存储在索引文件中的。用户进行搜索,也是以Document列表的形式返回。
8.Field
一个Document可以包含多个信息域,例如一篇文章可以包含“标题”、“正文”、“最后修改时间”等信息域,这些信息域就是通过Field在Document中存储的。
Field有两个属性可选:存储和索引。通过存储属性你可以控制是否对这个Field进行存储;通过索引属性你可以控制是否对该Field进行索引。这看起来似乎有些废话,事实上对这两个属性的正确组合很重要。
9.实现原理
文本倒排处理:
Lucene整体使用如图所示:
10.环境配置
下载lucene jar
导入jar 到项目中
11.创建索引
private String indexDir = "C:/Users/peixin/Desktop/luceneIndex";
private String dataDir = "C:/Users/peixin/Desktop/lucene-4.9.1/docs";
@Test
public void createIndex() throws IOException{
//指定索引存放目录
Directory directory = FSDirectory.open(new File(indexDir));
//创建基础分词器
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_4_9);
//对indexWriter进行配置
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
IndexWriter indexWriter = new IndexWriter(directory, config);
//循环遍历dataDir目录中的所有文件
Collection<File> listFiles = FileUtils.listFiles(new File(dataDir), TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
for (File file : listFiles) {
//将一个文件的文件名生成field信息域
TextField nameField = new TextField("fileName", file.getName(), Field.Store.YES);
//将一个文件的文件内容生成field信息域
TextField contentField = new TextField("content",FileUtils.readFileToString(file), Field.Store.YES);
//创建document,并添加两个信息域到其中
Document document = new Document();
document.add(nameField);
document.add(contentField);
//将doucument通过writer写入到索引目录中
indexWriter.addDocument(document);
}
indexWriter.close();
}
12.查询索引
@Test
public void search() throws IOException, ParseException{
//指定索引目录
Directory directory = FSDirectory.open(new File(indexDir));
//创建基础分词器
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_4_9);
//创建读入流
IndexReader indexReader = DirectoryReader.open(directory);
//通过indexReader 创建一个索引搜索器
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
//创建一个分析器并指定需要搜索的信息域和分词器
QueryParser queryParser = new QueryParser(Version.LUCENE_4_9, "content", analyzer);
//生成一个query,指定通过java搜索
Query parse = queryParser.parse("java");
//开始搜索,并指定搜索结果最多返回10个
TopDocs search = indexSearcher.search(parse, 10);
int totalHits = search.totalHits;
System.out.println("一共查询到 " + totalHits + "个结果");
//获取被搜索到的结果
ScoreDoc[] scoreDocs = search.scoreDocs;
for (int i = 0; i < scoreDocs.length; i++) {
ScoreDoc document = scoreDocs[i];
System.out.println("index " + document.shardIndex);
System.out.println("分数: " + document.score);
//获取document的id
int index = document.doc;
//通过document Id获取 document
Document doc = indexSearcher.doc(index);
System.out.println("name: " + doc.get("fileName"));
System.out.println("content: " + doc.get("content"));
System.out.println("================================");
}
}
13.其他功能
13.1 分词器
Lucene自带的StandardAnalyzer分词器,只能对英语进行分词。在对中文进行分词的时候采用了一元分词,即每一个中文作为一个词,如“我是中国人”,则分词结果为“我”,“是”,“中”,“国”,“人”,可以看出分词效果很差。在这里推荐一个比较好用的中文分词器IKAnalyzer。
13.2 停用词
停用词是指在信息检索中,为节省存储空间和提高搜索效率,在处理自然语言数据(或文本)之前或之后会自动过滤掉某些字或词,这些字或词即被称为Stop Words(停用词)。比如中文中“了”,“么”,“呢”,“的”等意义不大且在一篇文章中出现频率又很高的词,又比如英文中的”for”,”in”,”it”,”a”,”or”等词。
在使用IKAnalyzer分词器的时候,可以在IKAnalyzer.cfg.xml里配置相关信息,如下图: