Lucence学习
2,创建luence的步骤
3,api
// 创建索引
@Test
publicvoid testCreate() throws Exception{
//1创建文档对象
Document document = new Document();
// 创建并添加字段信息。参数:字段的名称、字段的值、是否存储,这里选Store.YES代表存储到文档列表。Store.NO代表不存储
document.add(newStringField("id", "1", Store.YES));
// 这里我们title字段需要用TextField,即创建索引又会被分词。StringField会创建索引,但是不会被分词
document.add(new TextField("title", "谷歌地图之父跳槽facebook", Store.YES));
//2索引目录类,指定索引在硬盘中的位置
Directory directory =FSDirectory.open(new File("indexDir"));
//3创建分词器对象
Analyzer analyzer = new StandardAnalyzer();
//4索引写出工具的配置对象
IndexWriterConfig conf = new IndexWriterConfig(Version.LATEST, analyzer);
//5创建索引的写出工具类。参数:索引的目录和配置信息
IndexWriter indexWriter = new IndexWriter(directory, conf);
//6把文档交给IndexWriter
indexWriter.addDocument(document);
//7提交
indexWriter.commit();
//8关闭
indexWriter.close();
}
1.1.1、使用工具查看索引
一个Document中可以有很多个不同的字段,每一个字段都是一个Field类的对象。
一个Document中的字段其类型是不确定的,因此Field类就提供了各种不同的子类,来对应这些不同类型的字段。
问题1:如何确定一个字段是否需要存储?
如果一个字段要显示到最终的结果中,那么一定要存储,否则就不存储
问题2:如何确定一个字段是否需要创建索引?
如果要根据这个字段进行搜索,那么这个字段就必须创建索引。
问题3:如何确定一个字段是否需要分词?
前提是这个字段首先要创建索引。然后如果这个字段的值是不可分割的,那么就不需要分词。例如:ID
1.1.1.1、Directory(目录类)
指定索引要存储的位置
FSDirectory:文件系统目录,会把索引库指向本地磁盘。
特点:速度略慢,但是比较安全
RAMDirectory:内存目录,会把索引库保存在内存。
特点:速度快,但是不安全
1.1.1.2、Analyzer(分词器类)
• 提供分词算法,可以把文档中的数据按照算法分词
这些分词器,并没有合适的中文分词器,因此一般我们会用第三方提供的分词器:
IK分词器官方版本是不支持Lucene4.X的,有人基于IK的源码做了改造,支持了Lucene4.X:
l 基本使用
引入IK分词器:
l 扩展词典和停用词典
IK分词器的词库有限,新增加的词条可以通过配置文件添加到IK的词库中,也可以把一些不用的词条去除:
1) 设置配置信息:Lucene的版本和分词器类型
2)设置是否清空索引库中的数据
1.1.1.1、IndexWriter(索引写出器类)
l 索引写出工具,作用就是实现对索引的增(创建索引)、删(删除索引)、改(修改索引)
l 可以一次创建一个,也可以批量创建索引
查询索引数据
@Test
publicvoid testSearch() throws Exception {
// 索引目录对象
Directory directory =FSDirectory.open(new File("indexDir"));
// 索引读取工具
IndexReader reader =DirectoryReader.open(directory);
// 索引搜索工具
IndexSearcher searcher = new IndexSearcher(reader);
// 创建查询解析器,两个参数:默认要查询的字段的名称,分词器
QueryParser parser = new QueryParser("title", newIKAnalyzer());
// 创建查询对象
Query query = parser.parse("谷歌地图之父拉斯");
// 搜索数据,两个参数:查询条件对象要查询的最大结果条数
// 返回的结果是按照匹配度排名得分前N名的文档信息(包含查询到的总条数信息、所有符合条件的文档的编号信息)。
TopDocs topDocs = searcher.search(query, 10);
// 获取总条数
System.out.println("本次搜索共找到" + topDocs.totalHits + "条数据");
// 获取得分文档对象(ScoreDoc)数组.SocreDoc中包含:文档的编号、文档的得分
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
// 取出文档编号
intdocID = scoreDoc.doc;
// 根据编号去找文档
Document doc = reader.document(docID);
System.out.println("id: " + doc.get("id"));
System.out.println("title: " + doc.get("title"));
// 取出文档得分
System.out.println("得分: " + scoreDoc.score);
}
}
/*
* 测试通配符查询
* ? 可以代表任意一个字符
* * 可以任意多个任意字符
*/
@Test
publicvoid testWildCardQuery() throws Exception {
// 创建查询对象
Query query = new WildcardQuery(new Term("title", "*歌*"));
search(query);
}
/*
* 测试普通词条查询
* 注意:Term(词条)是搜索的最小单位,不可再分词。值必须是字符串!
*/
@Test
publicvoid testTermQuery() throws Exception {
// 创建词条查询对象
Query query = new TermQuery(newTerm("title", "谷歌地图"));
search(query);
}
/*
* 测试模糊查询
*/
@Test
publicvoidtestFuzzyQuery() throws Exception {
// 创建模糊查询对象:允许用户输错。但是要求错误的最大编辑距离不能超过2
// 编辑距离:一个单词到另一个单词最少要修改的次数facebool -->facebook需要编辑1次,编辑距离就是1
// Query query = new FuzzyQuery(newTerm("title","fscevool"));
// 可以手动指定编辑距离,但是参数必须在0~2之间
Query query = new FuzzyQuery(new Term("title","facevool"),1);
search(query);
}
等。。。还有其他的一些查询方式,组合查询,数值范围查询,特殊查询
修改索引
* 注意:
* A:Lucene修改功能底层会先删除,再把新的文档添加。
* B:修改功能会根据Term进行匹配,所有匹配到的都会被删除。这样不好
* C:因此,一般我们修改时,都会根据一个唯一不重复字段进行匹配修改。例如ID
* D:但是词条搜索,要求ID必须是字符串。如果不是,这个方法就不能用。
* 如果ID是数值类型,我们不能直接去修改。可以先手动删除deleteDocuments(数值范围查询锁定ID),再添加。
/ 高亮显示
@Test
publicvoid testHighlighter() throws Exception {
// 目录对象
Directory directory =FSDirectory.open(new File("indexDir"));
// 创建读取工具
IndexReader reader =DirectoryReader.open(directory);
// 创建搜索工具
IndexSearcher searcher = new IndexSearcher(reader);
QueryParser parser = new QueryParser("title", newIKAnalyzer());
Query query = parser.parse("谷歌地图");
// 格式化器
Formatter formatter = new SimpleHTMLFormatter("<em>", "</em>");
Scorer scorer = new QueryScorer(query);
// 准备高亮工具
Highlighter highlighter = new Highlighter(formatter, scorer);
// 搜索
TopDocs topDocs = searcher.search(query, 10);
System.out.println("本次搜索共" + topDocs.totalHits + "条数据");
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
// 获取文档编号
intdocID = scoreDoc.doc;
Document doc = reader.document(docID);
System.out.println("id: " + doc.get("id"));
String title = doc.get("title");
// 用高亮工具处理普通的查询结果,参数:分词器,要高亮的字段的名称,高亮字段的原始值
String hTitle = highlighter.getBestFragment(newIKAnalyzer(), "title", title);
System.out.println("title: " + hTitle);
// 获取文档的得分
System.out.println("得分:" + scoreDoc.score);
}
}