一款 Apache托管的全文索引组件,纯Java实现。
用户—>服务器—>Lucene API—>索引库—>数据库/文档/web网页—>再返回。
当然搜索引擎这类都属于独立开发了一套自有的全文索引软件。并非直接用Apache Lucene这类开源组件。
以Java maven项目为例
<--...下为属性/版本定义部分-->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<lucene.version>9.12.1</lucene.version>
<hutool.all.version>5.8.26</hutool.all.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<--...下为依赖部分-->
<!-- Lucene Search engines must -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analysis-common</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queries</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>${lucene.version}</version>
</dependency>
<!-- Chinese word segmentation dependence -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>8.11.4</version>
</dependency>
提示:注意选择与自己jdk版本一致版本 Apache Lucene 与JDK版本对应关系-XQLEE'Blog
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Product {
/** 商品id **/
Long id;
/** 商品名称 **/
String name;
/** 商品价格 **/
Integer price;
/** 商品库存 **/
Integer stock;
/** 商品图片 **/
String image;
/** 商品品牌 **/
String brand;
}
/**
* 写索引/创建索引
*/
public static void createIndex() throws IOException {
//1.数据来源,模拟数据(正常业务情况来源于数据库)
Product p1 = new Product(1L,"小米手机15PRO",4500,20,"xiaomi15.jpg","小米");
Product p2 = new Product(2L,"红米手机K80PRO",2999,50,"redmi_k80.jpg","红米");
Product p3 = new Product(3L,"魅族手机20",2999,50,"meizu_20.jpg","魅族");
List<Product> products = new ArrayList<>();
products.add(p1);
products.add(p2);
products.add(p3);
//2.索引文档集合
//org.apache.lucene.document.Document
List<Document> docs = new ArrayList<Document>();
for (Product product : products) {
//文档创建
Document doc = new Document();
//Field.Store.YES - 存储原始值,索引查询后会用到,拿id查详情业务
doc.add(new TextField("id",product.getId().toString(),Field.Store.YES));
//Field.Store.YES - 存储原始值,搜索列表页面展示需要名称
doc.add(new TextField("name",product.getName(),Field.Store.YES));
/* ************************** 特殊字段 START ******************************/
//IntPoint - int类型索引存储,为了能使用范围查询
doc.add(new IntPoint("price",product.getPrice()));
//StoredField - 配合上面的IntPoint完成存储+索引(范围查询支持)
//目的:既要存储原始值又要值支持IntPoint的范围查询特性(后面查询用到)
doc.add(new StoredField("price",product.getPrice()));
/* ************************** 特殊字段 END ******************************/
//图片直接存储
doc.add(new StringField("image",product.getImage(),Field.Store.YES));
//品牌 - 存储
doc.add(new TextField("brand",product.getBrand(),Field.Store.YES));
docs.add(doc);
}
//3.分词器创建
//默认的StandardAnalyzer对中文不友好
// Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new SmartChineseAnalyzer();
//4.文件索引目录创建 (相对路径/绝对路径)
try (FSDirectory directory = FSDirectory.open(Paths.get("src/main/resources/lucene/index/products"))){
//5.创建IndexWriterConfig对象, 这个对象指定切分词使用的分词器
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
//6.创建IndexWriter输出流对象,指定输出位置和使用的config初始化对象。
try (IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);){
// 7.写入文档到索引库
for (Document doc : docs) {
indexWriter.addDocument(doc);
}
indexWriter.flush();
}
}
}
public static void searchIndex() throws ParseException, IOException {
// 1.创建分词器(对搜索的内容进行分词使用)。如华为手机可能拆分为 华为 手机
// Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new SmartChineseAnalyzer();
// 注意!!!:分词器要和创建索引的时候使用的分词器一模一样(不然搜索的时候就有问题)
// 2.创建查询对象 // 第一个arg默认查询域 //
QueryParser queryParser = new QueryParser("name", analyzer);
// 3.设置搜索关键词
Query query = queryParser.parse("小米");
// queryParser.parse("id:小米") 指定从id查,不指定就从默认的name域查
try (
// 4.设置Directory目录对象,指定索引库的位置(与写入索引目录一致)
Directory directory = FSDirectory.open(Paths.get("src/main/resources/lucene/index/products"));
// 5.创建输入流对象
IndexReader indexReader = DirectoryReader.open(directory);
){
// 6.创建搜索对象
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 7.搜索并返回结果
TopDocs topDocs_10 = indexSearcher.search(query, 10);
// 8.获取结果集
ScoreDoc[] scoreDocArray = topDocs_10.scoreDocs;
//打印结果
printResult(scoreDocArray,indexSearcher);
}
}
public static void printResult(ScoreDoc [] scoreDocArray,IndexSearcher indexSearcher) throws IOException {
// 9.遍历结果集
System.out.println("共查询到 " + scoreDocArray.length + " 条数据");
for (ScoreDoc temp : scoreDocArray) {
// 获取查询到的文档唯一ID,这个ID是Lucene在创建文档的时候自动分配的。
int docId = temp.doc;
// 通过文档ID读取文档
Document document = indexSearcher.doc(docId);
System.out.println("******************************************************************************************************");
System.out.println("id: " + document.get("id"));
System.out.println("name: " + document.get("name"));
System.out.println("price: " + document.get("price"));
}
}
查name 字段 关键词 小米
查 name字段 关键词 手机
查 brand 字段,关键词 红米
提示:字段名和查询关键词之间的冒号必须是英文半角冒号 :
public static void updateIndex() throws IOException {
//1.文档数据模拟
Document doc = new Document();
doc.add(new TextField("id","11",Field.Store.YES));
doc.add(new TextField("name","魅族手机15",Field.Store.YES));
doc.add(new IntPoint("price",1999));
doc.add(new StoredField("price",1999));
doc.add(new TextField("image","meizu15.jpg",Field.Store.YES));
//品牌 - 存储
doc.add(new TextField("brand","魅族",Field.Store.YES));
// 3.创建分词器
//默认的StandardAnalyzer对中文不友好
// Analyzer analyzer = new StandardAnalyzer();
Analyzer analyzer = new SmartChineseAnalyzer();
// 4.创建index目录对象,目录对象表示索引库的位置
try (
Directory directory = FSDirectory.open(Paths.get("src/main/resources/lucene/index/products"));
){
// 5.创建IndexWriterConfig对象, 这个对象指定切分词使用的分词器
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
// 6.创建IndexWriter输出流对象,指定输出位置和使用的config初始化对象。
try (IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);){
// 7.修改文档
// 提示:此处更新后 id = 1 的文档就没了,只有id=11的
indexWriter.updateDocument(new Term("id", "1"), doc);
}
}
}
/**
* 根据指定条件删除索引,例如:下面的根据id删除索引
* @throws IOException
*/
public static void deleteIndex() throws IOException {
//1.创建分词器
Analyzer analyzer = new StandardAnalyzer();
// 2.创建index目录对象,目录对象表示索引库的位置
try (Directory directory = FSDirectory.open(Paths.get("src/main/resources/lucene/index/products"));){
// 3.创建IndexWriterConfig对象, 这个对象指定切分词使用的分词器
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(analyzer);
// 4.创建IndexWriter输出流对象,指定输出位置和使用的config初始化对象。
try (IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);){
// 5.修改文档 (根据条件删除)
indexWriter.deleteDocuments(new Term("id", "11"));
// 删除所有 慎用
//indexWriter.deleteAll();
}
}
}
/**
* 删除所有索引
* @throws IOException
*/
public static void deleteAllIndex()throws IOException{
// 1.创建index目录对象,目录对象表示索引库的位置
try (Directory directory = FSDirectory.open(Paths.get("src/main/resources/lucene/index/products"));){
// 2.创建IndexWriterConfig对象, 这个对象指定切分词使用的分词器
IndexWriterConfig indexWriterConfig = new IndexWriterConfig();
// 3.创建IndexWriter输出流对象,指定输出位置和使用的config初始化对象。
try (IndexWriter indexWriter = new IndexWriter(directory, indexWriterConfig);){
// 4.删除所有 慎用
indexWriter.deleteAll();
}
}
}
https://blog.xqlee.com/article/2504281239158867.html