lucene供了完整的查询引擎和索引引擎,像商城之类的很多网站都会使用,包括大数据也在使用类似的工具,所以很有必要了解决一下,文章 主要是测试了lucene的索引创建、删除、更新及queryParser查询索引的方式。
创建lucene数据库,并创建book表,SQL语句内容如下:
USE `lucene`;
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_bin DEFAULT NULL,
`price` double DEFAULT NULL,
`pic` varchar(100) COLLATE utf8_bin DEFAULT NULL,
`description` varchar(5000) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
insert into `book`(`id`,`name`,`price`,`pic`,`description`) values (1,'java',11.23,'121323.jpg','给你推荐一个写得非常用心的Java基础教程:Java入门基础教程 | 天码营这个教程将Java的入门基础知识贯穿在一个实例中,逐步深入,可以帮助你快速进入Java编程的世界。万事开头难,逐步跟着这个教程走一遍,对Java应该就会有一种入门的感觉了。然后再去学习更高级的主题,或者更深入地学习其中的某些知识点。第1课 Java开发环境安装与配置 第2课 第一个Java程序 第3课 面向对象基础 第4课 基本数据类型 第5课 运算符 第6课 字符串操作 第7课 程序的控制流 第8课 静态变量与静态方法 第9课 Java集合 第10课 封装与继承 第11课 抽象类与接口 第12课 异常处理 第13课 综合实例 第14课 Eclipse的安装与使用\n\n作者:David\n链接:https://www.zhihu.com/question/25255189/answer/86898400\n来源:知乎\n著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。'),(2,'lucene solx ',12.55,'56465465.jpg','Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene是一套用于全文检索和搜寻的开源程式库,由Apache软件基金会支持和提供。Lucene提供了一个简单却强大的应用程式接口,能够做全文索引和搜寻。在Java开发环境里Lucene是一个成熟的免费开源工具。就其本身而言,Lucene是当前以及最近几年最受欢迎的免费Java信息检索程序库。人们经常提到信息检索程序库,虽然与搜索引擎有关,但不应该将信息检索程序库与搜索引擎相混淆。[1] '),(3,'java spring mybatis Struts2 springMVC hibernate',99.25,'6546545656.jpg','轻量——从大小与开销两方面而言Spring都是轻量的。完整的Spring框架可以在一个大小只有1MB多的JAR文件里发布。并且Spring所需的处理开销也是微不足道的。此外,Spring是非侵入式的:典型地,Spring应用中的对象不依赖于Spring的特定类。\r\n控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。\r\n面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。\r\n容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。\r\n框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。\r\nMVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。\r\n所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础'),(4,'天气你好啊哦咯看i我看',22.22,'365456564.jpg','G蛋白偶联受体(G Protein-Coupled Receptors,GPCRs)是一肽类膜蛋白受体的统称。这类受体的共同点是其立体结构中都有七个跨膜α螺旋,且其肽链的C端和连接第5和第6个跨膜螺旋的胞内环上都有G蛋白(鸟苷酸结合蛋白)的结合位点。目前为止,研究显示G蛋白偶联受体只见于真核生物之中,而且参与了很多细胞信号转导过程。在这些过程中,G蛋白偶联受体能结合细胞周围环境中的化学物质并激活细胞内的一系列信号通路,最终引起细胞状态的改变。已知的与G蛋白偶联受体结合的配体包括气味,费洛蒙,激素,神经递质,趋化因子等等。这些配体可以是小分子的糖类,脂质,多肽,也可以是蛋白质等生物大分子。一些特殊的G蛋白偶联受体也可以被非化学性的刺激源激活,例如在感光细胞中的视紫红质可以被光所激活。与G蛋白偶联受体相关的疾病为数众多,并且大约40%的现代药物都以G蛋白偶联受体作为靶点。'),(5,'爱奇艺',54.25,'adsfasdfa.jpg','爱奇艺,中国视频行业领先者。2010年4月22日正式上线,秉承“悦享品质”的品牌口号,积极推动产品、技术、内容、营销等全方位创新,为用户\r\n爱奇艺VIP代言人\r\n爱奇艺VIP代言人(6张)\r\n 提供丰富、高清、流畅的专业视频体验,致力于让人们平等、便捷地获得更多、更好的视频。截止到2015年7月,爱奇艺已成功构建了包含电商、游戏、电影票等业务在内、连接人与服务的视频商业生态,引领视频网站商业模式的多元化发展。[1] \r\n爱奇艺品质、青春、时尚的品牌调性深入人心,网罗了中国最广大的年轻用户群体。爱奇艺打造涵盖电影、电视剧、综艺、动漫在内的十余种类型的中国最大正版视频内容库,并通过“爱奇艺出品”战略的持续推动,让“纯网内容”进入真正意义上的全类别、高品质时代。同时,作为中国付费用户规模最大的视频网站,爱奇艺倡导“轻奢新主义”的VIP会员理念,主张人们对高品质生活细节的追求,坚持为广大VIP会员提供专属的海量精品内容,极致的视听体验,以及独有的线下会员服务。[1] \r\n2014年,爱奇艺在全球范围内率先建立起首个基于搜索和视频数据理解人类行为的视频大脑——爱奇艺大脑,用大数据指导内容的制作、生产、运营、消费。并通过强大的云计算能力,以及领先行业的带宽储备,和全球最庞大的视频分发网络,为用户提供更好的视频服务。在技术与内容双核驱动的新体验营销时代,爱奇艺创造性地提出了“iJOY悦享营销”客户服务价值观和方法论。通过多屏触点、创意内容、技术优化、互动参与、实现购买等路径全面提升ROI,让客户享受到创新营销带来的成功与快乐。[1] \r\n未来,爱奇艺将在多元化的内容储备、个性化的产品体验、定制化营销服务领域继续发力,引领视频体验革命。不断提升连接人与服务的能力,更好的改变人们的生活。[');
导入jar包,其中数据库的驱动我导入的是Mysql的,junit包有些自带,如果带的有可不导入
创建Book实体类
package com.ckinghan.bean;
import java.io.Serializable;
public class Book implements Serializable {
// 图书ID
private Integer id;
// 图书名称
private String name;
// 图书价格
private Float price;
// 图书图片
private String pic;
// 图书描述
private String description;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Book [id=" + id + ", name=" + name + ", price=" + price + ", pic=" + pic + ", description="
+ description + "]";
}
}
创建BookDao接口,并创建queryBooks方法
import java.util.List;
import com.ckinghan.bean.Book;
public interface BookDao {
/**
* 查询所有的BOOK内容
* @创建时间:2017年10月7日16:15:10
*/
public List queryBooks();
}
创建BookDao的实现类BookDaoImpl
package com.ckinghan.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.ckinghan.bean.Book;
public class BookDaoImpl implements BookDao {
@Override
public List queryBooks() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
List books = new ArrayList();
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/lucene","root","root");
String sql = "select * from book";
preparedStatement = connection.prepareStatement(sql);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
Book book = new Book();
book.setId(resultSet.getInt("id"));
book.setName(resultSet.getString("name"));
book.setPic(resultSet.getString("pic"));
book.setPrice(resultSet.getFloat("price"));
book.setDescription(resultSet.getString("description"));
books.add(book);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return books;
}
}
创建测试文件:
package com.ckinghan.lucene;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.FloatField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.junit.Test;
import com.ckinghan.bean.Book;
import com.ckinghan.dao.BookDao;
import com.ckinghan.dao.BookDaoImpl;
public class TwoCreateIndex {
/**
* 创建并在指定的位置写入lucene索引文件
* @创建时间:2017年10月7日20:58:47
*/
@Test
public void createIndex() throws IOException {
// 查询数据
BookDao bookDao = new BookDaoImpl();
List books = bookDao.queryBooks();
// 定义一个Document集合
List documents = new ArrayList<>();
// 定义document对象
Document document;
// 遍历查询出来的数据
for (Book book : books) {
// 实例化document对象
document = new Document();
// 不进行分词,只进行索引、存储
Field id = new StringField("id", book.getId().toString(), Store.YES);
// 进行分词、索引、存储
Field name = new TextField("name", book.getName(), Store.YES);
// 对数值类型(float/double/int/long)不进行分词,只进行索引、存储
Field price = new FloatField("price", book.getPrice(), Store.YES);
// 不进行分词、索引,只存储
Field pic = new StoredField("pic", book.getPic());
// 进行分词、索引,但不存储
Field description = new TextField("description", book.getDescription(), Store.NO);
// 将Field放到document对象中
document.add(id);
document.add(name);
document.add(price);
document.add(pic);
document.add(description);
// 将document放到documents集合中
documents.add(document);
}
// 创建一个标准分词对象
Analyzer analyzer = new StandardAnalyzer();
// 索引库的位置
Directory directory = FSDirectory.open(new File("D:" + File.separator + "lucene_index" + File.separator));
// 索引序列化的配置
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
// 创建索引序列化(写入流)对象
IndexWriter writer = new IndexWriter(directory, config);
// 将documents对象循环写入到指定的索引目录 中
for (Document doc : documents) {
writer.addDocument(doc);
}
// 关闭流对象
writer.close();
}
/**
* 通过指定的lucene索引目录查询指定的数据 @创建时间:2017年10月7日21:14:30
*/
@Test
public void readerIndex() throws ParseException, IOException {
// 创建QueryParser对象,并指定要查询的索引域及分词对象
QueryParser queryParser = new QueryParser("name", new StandardAnalyzer());
// 创建Query对象,指定查询条件
Query query = queryParser.parse("name:java OR string");
// 指定要查询的lucene索引目录,必须与存储的索引目录一致
Directory directory = FSDirectory.open(new File("D:" + File.separator + "lucene_index" + File.separator));
// 通过指定的查询目录文件地址创建IndexReader流对象
IndexReader reader = DirectoryReader.open(directory);
// 通过IndexReader流对象创建IndexSearcher
IndexSearcher searcher = new IndexSearcher(reader);
// 执行查询语句,获取返回的TopDocs对象(参数中的100为取出的数据条数)
TopDocs search = searcher.search(query, 100);
// 获取查询关键字获得的数据总数
int totalHits = search.totalHits;
System.out.println("通过查询条件总共查询到的数据量为:" + totalHits);
System.out.println();
// 获取查询到的数据
ScoreDoc[] scoreDocs = search.scoreDocs;
for (ScoreDoc doc : scoreDocs) {
// 获取查询到的索引ID
int docId = doc.doc;
// 根据索引查询数据
Document document = searcher.doc(docId);
// 输出查询到的数据
System.out.println("ID数据为:" + document.get("id"));
System.out.println("name数据为:" + document.get("name"));
System.out.println("price数据为:" + document.get("price"));
System.out.println("pic数据为:" + document.get("pic"));
System.out.println("description数据为:" + document.get("description"));
System.out.println("******************************");
System.out.println();
System.out.println();
}
// 关闭流
reader.close();
}
public void queryIndex(String id) throws IOException, ParseException {
Analyzer analyzer = new StandardAnalyzer();
// 创建指定查询域、分词对象创建QueryParser对象
QueryParser parser = new QueryParser("id", analyzer);
// 指定查询条件,创建query对象
Query query = parser.parse(new StringBuilder("id:").append(id).toString());
Directory directory = FSDirectory.open(new File("D:" + File.separator + "lucene_index" + File.separator));
// 创建reader流对象,打开指定的lucene索引目录
IndexReader reader = DirectoryReader.open(directory);
// 通过创建的流对象创建查询对象searcher
IndexSearcher searcher = new IndexSearcher(reader);
// 通过查询对象查询指定条件的数据
TopDocs topDocs = searcher.search(query, 10);
// 获取查询的数据总量
int totalHits = topDocs.totalHits;
// 将查询返回的索引数据赋值给scoreDocs对象
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
// 如果查询的数据不存在,输出提示信息
if (scoreDocs == null || scoreDocs.length == 0) {
System.out.println("未查询到ID为" + id + "的数据,删除ID为" + id + "的数据成功");
} else {
// 如果查询的数据未删除成功,则输出相应的数据
for (ScoreDoc doc : scoreDocs) {
// 获取查询到的索引id
int docId = doc.doc;
// 通过查询到的索引id查询索引中对应的文档域中的内容
Document document = searcher.doc(docId);
// 输出查询到的数据
System.out.println("ID数据为:" + document.get("id"));
System.out.println("name数据为:" + document.get("name"));
System.out.println("price数据为:" + document.get("price"));
System.out.println("pic数据为:" + document.get("pic"));
System.out.println("description数据为:" + document.get("description"));
System.out.println("******************************");
System.out.println();
System.out.println();
}
}
// 关闭流对象
reader.close();
}
/**
* 根据查询条件删除lucene索引及文档数据 @创建时间:2017年10月7日21:58:33
*/
@Test
public void deleteIndex() throws IOException, ParseException {
// 创建分词对象
Analyzer analyzer = new StandardAnalyzer();
// 指定lucene索引目录地址
Directory directory = FSDirectory.open(new File("D:" + File.separator + "lucene_index" + File.separator));
// 创建配置对象
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
// 通过指定的索引目录地址、配置对象创建IndexWriter流对象
IndexWriter writer = new IndexWriter(directory, config);
// 删除索引目录 id = 1的数据
writer.deleteDocuments(new Term("id", "1"));
// 清空索引及存档的所有数据
// writer.deleteAll();
// 关闭流对象
writer.close();
// 查询id为1的数据是否删除成功
queryIndex("1");
}
/**
* 更新索引
* @创建时间:2017年10月7日22:13:07
*/
@Test
public void updateIndex() throws IOException, ParseException {
//创建分词对象
Analyzer analyzer = new StandardAnalyzer();
//指定索引目录地址
Directory directory = FSDirectory.open(new File("D:" + File.separator + "lucene_index" + File.separator));
//创建配置对象
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, analyzer);
//通过配置、目录参数创建流对象
IndexWriter writer = new IndexWriter(directory, config);
//创建document对象
Document doc = new Document();
//添加索引数据到doc对象
doc.add(new TextField("id", "7", Store.YES));
//将新添加的doc数据替换索引中已经有的id为2的数据
//执行步骤如下:查询数据--》查询到或未查询到--》替换/添加doc数据
writer.updateDocument(new Term("id", "2"), doc);
//关闭流
writer.close();
// 查询id为2的数据是否更改成功,如果更改成功,就没有了id为2的数据
queryIndex("2");
// 查询id为7的数据是否替换写入索引成功
queryIndex("7");
}
}
执行方法createIndex()创建索引效果如下图所示,已经生成了索引文件。
执行方法readerIndex()查询指定的数据效果如下所示:
通过查询条件总共查询到的数据量为:2
ID数据为:1
name数据为:java
price数据为:11.23
pic数据为:121323.jpg
description数据为:null
******************************
ID数据为:3
name数据为:java spring mybatis Struts2 springMVC hibernate
price数据为:99.25
pic数据为:6546545656.jpg
description数据为:null
******************************
执行方法deleteIndex() 根据查询条件删除lucene索引及文档数据效果如下所示:
未查询到ID为1的数据,删除ID为1的数据成功
执行方法updateIndex() 更新索引效果如下所示:
未查询到ID为2的数据,删除ID为2的数据成功
ID数据为:7
name数据为:null
price数据为:null
pic数据为:null
description数据为:null
******************************