这个是以下代码的完整项目,或许对你们有所帮助 《Lucene6.6.2API示例下载》
网上关于Luence6.x及以上的资料比较少,大多都是4.x的,API修改的修改、废弃的废弃
这里就简单介绍一些常用API的使用
public class Book {
// 图书ID
private Integer id;
// 图书名称
private String name;
// 图书价格
private Float price;
// 图书图片
private String pic;
// 图书描述
private String description;
// 省略getter、setter方法
}
使用JDBC采集数据后封装成Java对象,重点不在这,所以不多做介绍
IndexManager.java
@Test
public void createIndex() throws Exception {
// 清除原先的数据
deleteIndex();
// 采集数据
List findAllBooks = new BookDaoImpl().findAllBooks();
// 将采集到的数据封装到Document对象中
// 一个对象(记录)= 一个Document
// 一个属性(字段)= 一个Field
List documents = new ArrayList();
Document document = null;
for (Book book : findAllBooks) {
document = new Document();
// Store:Yes则将数据存到文档域中,NO则相反
// IntPoint:不分词、索引、不存储,可用于范围搜索,与FloatPoint、DoublePoint、LongPoint用法一样
Field idIndex = new IntPoint("idIndex", book.getId());
// 因为IntPoint只生成索引、存储到索引库,所以如果搜索时需要此数据,则需要再存储一份到文档库
Field idString = new StoredField("idString", book.getId().toString());
// TextField:分词、索引、存储
Field name = new TextField("name", book.getName(), Store.YES);
// FloatDocValuesField:不分词、索引、不存储,可用于排序,与DoubleDocValuesField、NumericDocValuesField、SortedNumericDocValuesField一样
Field priceIndex = new FloatDocValuesField("priceIndex", book.getPrice());
Field priceString = new StoredField("priceString", book.getPrice().toString());
// StoredField:不分词、不索引、存储
Field pic = new StoredField("pic", book.getPic());
// TextField:分词、索引、不存储
Field description = new TextField("description", book.getDescription(), Store.NO);
// 将field域设置到Document对象中
document.add(idIndex);
document.add(idString);
document.add(name);
document.add(priceIndex);
document.add(priceString);
document.add(pic);
document.add(description);
documents.add(document);
}
// 创建分词器,自带的标准分词器
Analyzer analyzer = new StandardAnalyzer();
// 创建IndexWriter
Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
IndexWriterConfig config = new IndexWriterConfig(analyzer);
IndexWriter writer = new IndexWriter(directory, config);
// 通过IndexWriter把Document写到索引库中
for (Document doc : documents) {
writer.addDocument(doc);
}
// 关闭资源
writer.close();
}
@Test
public void deleteIndex() throws Exception {
// 创建分词器,标准分词器
Analyzer analyzer = new StandardAnalyzer();
// 创建IndexWriter
IndexWriterConfig cfg = new IndexWriterConfig(analyzer);
Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
// 创建IndexWriter
IndexWriter writer = new IndexWriter(directory, cfg);
// Terms
// writer.deleteDocuments(new Term("idIndex", "1"));
// 删除全部(慎用)
writer.deleteAll();
writer.close();
}
@Test
public void updateIndex() throws Exception {
// 创建分词器,标准分词器
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig cfg = new IndexWriterConfig(analyzer);
Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
// 创建IndexWriter
IndexWriter writer = new IndexWriter(directory, cfg);
// 第一个参数:指定查询条件
// 第二个参数:修改之后的对象
// 修改时如果根据查询条件,可以查询出结果,则将以前的删掉,然后覆盖新的Document对象,如果没有查询出结果,则新增一个Document
// 修改流程即:先查询,再删除,在添加
Document doc = new Document();
doc.add(new TextField("name", "javaSE", Store.YES));
writer.updateDocument(new Term("name", "javase"), doc);
writer.close();
}
IndexSearch.java
private void doSearch(Query query, Sort sort) {
// 创建IndexSearcher
// 指定索引库的地址
try {
Directory directory = FSDirectory.open(FileSystems.getDefault().getPath("C:\\repository\\lucene"));
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
// 通过searcher来搜索索引库
// 第二个参数:指定需要显示的顶部记录的N条
// 第三个参数:排序条件
TopDocs topDocs = null;
if(sort != null) {
topDocs = searcher.search(query, 10, sort);
}
else {
topDocs = searcher.search(query, 10);
}
// 根据查询条件匹配出的记录总数
int count = topDocs.totalHits;
System.out.println("匹配出的记录总数:" + count);
// 根据查询条件匹配出的记录
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
// 获取文档的ID
int docId = scoreDoc.doc;
// 通过ID获取文档
Document doc = searcher.doc(docId);
System.out.println("商品ID:" + Integer.parseInt(doc.get("idString")));
System.out.println("商品名称:" + doc.get("name"));
System.out.println("商品价格:" + Float.parseFloat(doc.get("priceString")));
System.out.println("商品图片地址:" + doc.get("pic"));
System.out.println("==========================");
// System.out.println("商品描述:" + doc.get("description"));
}
// 关闭资源
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void indexSearch() throws Exception {
// 创建query对象
// 使用QueryParser搜索时,需要指定分词器,搜索时的分词器要和索引时的分词器一致
// 第一个参数:默认搜索的域的名称
QueryParser parser = new QueryParser("description", new StandardAnalyzer());
// 通过queryparser来创建query对象
// 参数:输入的lucene的查询语句(关键字一定要大写)
// Query query = parser.parse("java AND name:lucene");
// Query query = parser.parse("java OR name:lucene");
Query query = parser.parse("java NOT name:lucene");
// 创建浮点数排序字段,默认为false:升序;true:降序
SortField sortField = new SortField("priceIndex", Type.FLOAT, false);
Sort sort = new Sort();
sort.setSort(sortField);
doSearch(query, sort);
}
@Test
public void termQuery() {
// 创建TermQuery对象
Query query = new TermQuery(new Term("description", "java"));
doSearch(query, null);
}
@Test
public void newRangeQuery() {
// 创建IntPoint对象,范围查找
Query query = IntPoint.newRangeQuery("idIndex", 2, 3);
doSearch(query, null);
}
@Test
public void booleanQuery() {
// 创建TermQuery对象
Query query1 = new TermQuery(new Term("name", "java"));
// 创建NumericRangeQuery对象
// 参数:域的名称、最小值、最大值、是否包含最小值、是否包含最大值
Query query2 = IntPoint.newRangeQuery("idIndex", 1, 5);
// 组合关系代表的意思如下:
// 1、MUST和MUST表示“与”的关系,即“交集”。
// 2、MUST和MUST_NOT前者包含后者不包含。
// 3、MUST_NOT和MUST_NOT没意义
// 4、SHOULD与MUST表示MUST,SHOULD失去意义;
// 5、SHOUlD与MUST_NOT相当于MUST与MUST_NOT。
// 6、SHOULD与SHOULD表示“或”的概念。
BooleanClause bc1 = new BooleanClause(query1, Occur.MUST);
BooleanClause bc2 = new BooleanClause(query2, Occur.MUST);
// Lucene 6.x中BooleanQuery与4.x中的BooleanQuery用法不一样
BooleanQuery boolQuery = new BooleanQuery.Builder().add(bc1).add(bc2).build();
System.out.println(boolQuery);
doSearch(boolQuery, null);
}
@Test
public void multiFieldQueryParser() throws Exception {
// 创建MultiFieldQueryParser
// 默认搜索的多个域的域名
String[] fields = { "name", "description" };
Analyzer analyzer = new StandardAnalyzer();
//
Map boosts = new HashMap();
boosts.put("name", 200f);
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer, boosts);
//Query query = parser.parse("java");
Query query = parser.parse("name:java OR description:lucene");
System.out.println(query);
doSearch(query, null);
}
官方文档:《Lucene 6.2.1 core API》
相关度排序就是查询关键字与查询结果的匹配相关度。匹配越高的越靠前。Lucene是通过打分来进行相关度排序的。
1、 根据词计算词的权重
2、 根据词的权重进行打分
词的权重:词指的就是term。也就是说一个term对一个文档的重要性,就叫词的权重。
Tf越高,说明词的权重越高
Df越高,说明词的权重越低
以上是自然打分的规则。
Boost:加权值,默认是1.0f。Boost值是设置到Field域上的。
设置加权值可以在创建索引时设置,也可以在查询时设置。
// 图书ID
// 不分词、索引、存储 StringField
Field id = new StringField("id", "1", Store.YES);
// 图书描述
// 分词、索引、不存储 TextField
Field description = new TextField("description", "这是一本书", Store.NO);
// 设置boost值
if (book.getId() == 4)
description.setBoost(100f);
// 将field域设置到Document对象中
document.add(id);
document.add(description);
在MultiFieldQueryParser创建时设置boost值。
@Test
public void multiFieldQueryParser() throws Exception {
// 创建MultiFieldQueryParser
// 默认搜索的多个域的域名
String[] fields = { "name", "description" };
Analyzer analyzer = new StandardAnalyzer();
Map boosts = new HashMap();
boosts.put("name", 200f);
MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer, boosts);
// Query query = parser.parse("name:lucene OR description:lucene");
Query query = parser.parse("java");
System.out.println(query);
doSearch(query);
}