<%@ page language="java" contentType="text/html; charset=utf-8"%>
<%@page import="com.liuyang.lucene.ProductLucene"%>
<%@page import="com.liuyang.util.PageModel"%>
<%
ProductLucene productLucene = new ProductLucene();
int i = productLucene.getProductLucene();
PageModel pm = productLucene.searchProduct("apple",0,10);
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>测试页面</title>
</head>
<body>
<%out.println("共有:"+i+"条记录生成索引。");%> <br>
<%out.println("查询结果共有:"+pm.getDatas().size()+"条");%> <br>
<%out.println("id分别是:");%> <br>
<% for(int j=0;j<pm.getDatas().size();j++){
out.println(pm.getDatas().get(j)+"<br />");
}
%>
</body>
</html>
|
package com.liuyang.lucene;
import java.io.BufferedReader;
import java.io.File;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
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.index.IndexWriter;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.apache.lucene.search.IndexSearcher;
import com.liuyang.util.PageModel;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TopDocs;
/**
* 商品相关的Lucene
* @author liuyang_js
*
*/
public class ProductLucene {
private static int TOP_NUM = 1000;//显示前1000条结果
static{
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
} catch (Exception e1) {
e1.printStackTrace();
}
}
/**
* 获得连接
*/
public static Connection getCon(){
Connection con=null;
String url = "jdbc:mysql://localhost:3306/test";
String userName="root";
String password="root";
try {
con = DriverManager.getConnection(url,userName,password);
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
/**
* 生成商品索引
* @return 共生成了
*/
public int getProductLucene(){
//声明索引文件
File LuceneFile=new File("productlucene");
//声明查询sql
String sql = "select ProductId,ProductName,ProductIntr from product";
//声明打开索引对象指针
Directory directory = null;
int i = 0;
try {
//为打开索引对象指针赋值
directory = FSDirectory.open(LuceneFile);
//声明分词器,此处使用的是标准分次器,即当前lucene版本的默认分词器。
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
//创建IndexWriter对象,第一个参数是Directory,第二个是分词器,
//第三个表示是否是创建,如果为false为在此基础上面修改,
//第四表示表示分词的最大值,比如说new IndexWriter.MaxFieldLength(2),就表示两个字一分,一般用IndexWriter.MaxFieldLength.LIMITED
IndexWriter writer = new IndexWriter(directory, analyzer, true,
IndexWriter.MaxFieldLength.LIMITED);
//SetMergeFactor是控制segment合并频率的,其决定了一个索引块中包括多少个文档,
//当硬盘上的索引块达到多少时,将它们合并成一个较大的索引块。
//当MergeFactor值较大时,生成索引的速度较快。
//MergeFactor的默认值是10,建议设置大一些,个人认为1000可以。
writer.setMergeFactor(1000);
//获取数据库连接
Connection con = getCon();
//声明PreparedStatement和ResultSet对象
PreparedStatement ps=con.prepareStatement(sql);
ResultSet rs =ps.executeQuery();
while(rs.next()){
i++;
StringBuffer sb = new StringBuffer();
//声明Document对象,在lucene中每个Document相当于数据库中的一条记录
Document doc = new Document();
//像Document对象增加Field,每个Field相当于数据库中的一个字段。
//Field构造的四个参数,第一个代表名称,第二个代码内容
//第三个是否存储,第四个是否分词
doc.add(new Field("ProductId", rs.getLong(1)+"", Field.Store.YES, Field.Index.NOT_ANALYZED)) ;
//因为第三个字段是text类型,所以需要使用流来读取
Reader reader= rs.getCharacterStream(3);
if(reader!=null){
BufferedReader br= new BufferedReader(reader);
String line = br.readLine();
while(line != null){
sb.append(line);
line = br.readLine();
}
//对Document对象增加"All"字段,字段由商品名和商品简介组合而成,不存储,分词
doc.add(new Field("All", sb.append(" ").append(rs.getString(2)).toString(), Field.Store.NO, Field.Index.ANALYZED)) ;
reader.close();
br.close();
}else{
//如果商品简介取不到,则对Document对象增加"All"字段,内容为商品名,不存储,分词
doc.add(new Field("All", rs.getString(2), Field.Store.NO, Field.Index.ANALYZED)) ;
}
//使用writer将Document写入。
writer.addDocument(doc);
}
//关闭数据库连接使用的对象。
ps.close();
rs.close();
con.close();
//对索引文件进行压缩、优化,此操作后所有索引文件将会变成一个。
writer.optimize();
//关闭writer
writer.close();
//关闭directory
directory.close();
} catch (Exception e) {
e.printStackTrace();
}
return i;
}
/**
*
* @param keyWord 关键字
* @param indexstart 开始位置
* @param length 一共查询多少条记录
* @return 分页对象
* @throws Exception
*/
public PageModel searchProduct(String keyWord,int indexstart,int length) throws Exception{
//声明pageModel对象,分页对象
PageModel pm = new PageModel();
//声明IndexSearcher
IndexSearcher searcher = null;
//声明FSDirectory
FSDirectory directory =null;
//声明用于存放查询结果集的list
List list = new ArrayList();
//声明分词器,此处使用的是标准分次器,即当前lucene版本的默认分词器。此处需要和生成索引文件的分词器一致。
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_CURRENT);
//打开索引文件,此处文件应该为生成索引的文件地址。
directory =FSDirectory.open(new File("productlucene"));
//使用searcher打开索引文件
searcher =new IndexSearcher(directory);
//QueryParser是lucene中用来查询的类,构造有三个参数,第一个参数是分词器的版本,
//第二个参数是查询的字段,第三个字段是分词器。
QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "All", analyzer);
//通过parser对象检索关键词,得到Query对象。
Query query = parser.parse(keyWord);
//通过searcher对象开始查询,调用search方法,有两个参数,
//第一个是query对象,第二个是查询上限是多少条
TopDocs hits = searcher.search(query, TOP_NUM);
//通过开始记录的位置和要查询多少条记录,将末尾记录的位置算出来
int indexend = indexstart+length;
//如果结尾的记录位置大于查询出来的结果总数,那么使用结果总数,否则使用结尾的记录位置
indexend = indexend>hits.totalHits?hits.totalHits:indexend;
//根据开始位置和结尾位置循环。
for (int i = indexstart; i < indexend; i++) {
//使用下面代码可以返回第i条记录 在索引文件中的id
int id = hits.scoreDocs[i].doc;
//通过此ID 可以查询出Document对象
Document doc = searcher.doc(id);
//通过Document的get方法可以获得到他的属性值
long productId = Long.parseLong(doc.get("ProductId"));
//将查询出来的结果放到list中
list.add(productId);
}
//声明totle对象 存放查询结果总数
int totle =hits.totalHits>1000?1000:hits.totalHits;
//对pm对象设定属性
pm.setDatas(list);
pm.setTotal(totle);
if(totle%length != 0){
pm.setPageCount(totle/length+1);
}else{
pm.setPageCount(totle/length);
}
//关闭searcher和directory
searcher.close();
directory.close();
return pm;
}
}
|