Lucene的学习
学习的三个问题
什么是Lucene?
Lucene是apache下的一个开源的全文检索引擎工具包。
什么是全文检索?
全文检索就是先分词,创建索引,再执行搜索的过程。
什么是分词?
分词就是将一段文字,分成一个个单词。
全文检索就是将一段文字分成一个个单词,然后去查询。
为什么要学习Lucene?
全文检索是我们在生活中使用较为广泛的一种技术。如在电商网站搜索“java教程”这一关键词时,他会显示java有关和教程有关的,以及java教程有关的商品。如果只是显示单一的java教程这样条件下的商品,很难满足顾客。因此我们就要学习如何将多种查询结果显示在页面上,这样就推出了全文检索。Lucene就是其中的一种。
我们之前学习过模糊查询。但也不能解决我们的问问题。
怎么学习Lucene?
索引流程:采集数据->构建文档对象->创建索引(将文档写入索引库)
搜索流程:创建查询->执行搜索->渲染搜索结果
如下是入门示例:
1.采集数据
public List getData() {
// 连接
Connection conn = null;
// 执行预编译
PreparedStatement ps = null;
// 结果集
ResultSet rs = null;
// 图书列表
List books = new ArrayList();
// 创建一个book
Book book = null;
try {
// 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
// 连接数据库
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/lucene", "root", "root");
// sql语句
String sql = "SELECT id, name, price, pic, description FROM book ";
// 创建preparedstatement
ps = conn.prepareStatement(sql);
// 获得结果集
rs = ps.executeQuery();
// 解析结果集
while (rs.next()) {
book = new Book();
book.setId(rs.getInt("id"));
book.setName(rs.getString("name"));
book.setPic(rs.getString("pic"));
book.setPrice(rs.getFloat("price"));
book.setDescription(rs.getString("description"));
books.add(book);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != conn) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (null != ps) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (null != rs) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return books;
}
2.将数据转换成Lucene文档
public List getDocuments(List books) {
// document对象集合
List docs = new ArrayList();
// document 对象
Document doc = null;
for (Book book : books) {
doc = new Document();
// document文档由域组成
//id 不需要分词,不需要索引,需要存储
StoredField id = new StoredField("id", book.getId());
// name 分词 索引 存储
TextField name = new TextField("name", book.getName(), Store.YES);
//图片 不分词, 不索引,存储
StoredField pic = new StoredField("pic", book.getPic());
//price 分词,索引,存储
FloatField price = new FloatField("price", book.getPrice(), Store.YES);
//描述desc 分词,索引 不需要存储
TextField desc = new TextField("desc", book.getDescription(), Store.NO);
doc.add(id);
doc.add(name);
doc.add(pic);
doc.add(price);
doc.add(desc);
docs.add(doc);
}
return docs;
}
3.创建索引库
@Test
public void createIndex() {
try {
// 1、创建一个分词器
//Analyzer analyzer = new StandardAnalyzer();
// 2、指定索引库的目录,在磁盘上的位置。
Directory directory = FSDirectory.open(new File("E:\\Lucene"));
// 3、创建indexwriter写对象,将文档写入索引库
// 创建一个配置类
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_3, new IKAnalyzer());
// 创建一个writer对象
IndexWriter writer = new IndexWriter(directory, config);
// 4、将文档写入索引库,完成分词,创建索引的过程
BookDao dao = new BookDao();
writer.addDocuments(dao.getDocuments(dao.getData()));
// 5、提交事务
writer.commit();
// 6、关闭资源流
writer.close();
System.out.println("创建索引库成功...");
} catch (IOException e) {
e.printStackTrace();
}
}
4.完成查询
//@Test
public void doSearch(Query query) {
try {
// 1、创建分词器,标准分词器 StandardAnalyzer
Analyzer analyzer = new StandardAnalyzer();
// 2、指定索引库
Directory directory = FSDirectory.open(new File("E:\\Lucene"));
// 3、创建查询对象query
// 两个参数:第一个为默认的搜索域
// 第二个为:分词器
QueryParser parser = new QueryParser("name", analyzer);
// 指定搜索的域: 格式为: 域名:关键词
query = parser.parse("name:mybatis");
// 4、创建indexSearcher,用来执行搜索
IndexReader reader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(reader);
// 5、执行搜索
// 两个参数分别代表为:第一个表示查询对象
// 第二个表示默认搜索的条数,用来做分页,相当于数据库中每页的容量pageSize
TopDocs docs = searcher.search(query, 10);
int totalHits = docs.totalHits;
System.out.println("共搜索到" + totalHits + "条满足条件的数据!");
ScoreDoc[] scoreDocs = docs.scoreDocs;
for (ScoreDoc scoreDoc : scoreDocs) {
int docId = scoreDoc.doc;
Document doc = searcher.doc(docId);
System.out.println("图书的id:" + doc.get("id"));
System.out.println("图书的名称:" + doc.get("name"));
System.out.println("图书的图片:" + doc.get("pic"));
System.out.println("图书的价格:" + doc.get("price"));
System.out.println("图书的描述信息:" + doc.get("desc"));
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}