package com.gaibuy.foundation.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.document.Document;
import org.apache.lucene.document.DoubleField;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.document.IntField;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.CorruptIndexException;
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.Sort;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleFragmenter;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.wltea.analyzer.lucene.IKAnalyzer;
/**
* 商品lucene工具类
*
*/
public class GoodsLuceneUtil {
private static File index_file = null;
private static Analyzer analyzer;
private static QueryParser parser;
private static String index_path;
private int textmaxlength = 2000;
private static String prefixHTML = "<font color='red'>";
private static String suffixHTML = "</font>";
public GoodsLuceneUtil(String indexPath) {
index_path = indexPath;
analyzer = new IKAnalyzer(true);
parser = new QueryParser(Version.LUCENE_4_9, GoodsLuceneVo.TITLE, analyzer);
}
public void setIndex_path(String path) {
index_path = path;
}
/**
* 创建索引阅读器
*
* @param directoryPath
* 索引目录
* @return
* @throws IOException
* 可能会抛出IO异常
*/
public static IndexReader createIndexReader(String index_path) throws IOException {
return DirectoryReader.open(FSDirectory.open(new File(index_path)));
}
/**
* 创建索引查询器
*
* @param directoryPath
* 索引目录
* @return
* @throws IOException
*/
public static IndexSearcher createIndexSearcher(String index_path) throws IOException {
return new IndexSearcher(createIndexReader(index_path));
}
/**
* 创建索引查询器
*
* @param reader
* @return
*/
public static IndexSearcher createIndexSearcher(IndexReader reader) {
return new IndexSearcher(reader);
}
/**
* Lucene分页查询
*
* @param directoryPath
* @param query
* @param page
* @throws IOException
*/
public static void pageQuery(Query query, LuceneResult result, Sort sort) throws IOException {
IndexSearcher searcher = createIndexSearcher(index_path);
result.setRows(searchTotalRecord(searcher, query));
ScoreDoc after = getLastScoreDoc(result.getCurrentPage(), result.getPageSize(), query, searcher, sort);
TopDocs topDocs = searcher.searchAfter(after, query, result.getPageSize(), sort);
// 设置总记录数
List<Document> docList = new ArrayList<Document>();
System.out.println(topDocs.totalHits + "topDocs.totalHits.......................");
ScoreDoc[] docs = topDocs.scoreDocs;
for (ScoreDoc scoreDoc : docs) {
int docID = scoreDoc.doc;
Document document = searcher.doc(docID);
docList.add(document);
}
result.setDoc_list(docList);
searcher.getIndexReader().close();
}
/**
* 商品搜索
*
* @param params
* @param directoryPath
* @param begin_price
* @param end_price
* @param result
* @param sort
* @return
* @throws ParseException
* @throws IOException
*/
public LuceneResult goodsPage(String params, double begin_price, double end_price, LuceneResult result, Sort sort)
throws ParseException, IOException {
// 组件参数
params = goodsBuilderParams(params, begin_price, end_price);
try {
parser.setAllowLeadingWildcard(true);
Query query = parser.parse(params);
pageQuery(query, result, sort);
List<GoodsLuceneVo> goodsVoList = builderVoList(result.getDoc_list(), query);
result.setGoodsVo_list(goodsVoList);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 创建索引
*
* @param list
* @throws IOException
*/
public void writeIndex(List<GoodsLuceneVo> list) throws IOException {
IndexWriter writer = openIndexWriter();
try {
for (GoodsLuceneVo lucenceVo : list) {
Document document = builderDocument(lucenceVo);
writer.addDocument(document);
}
writer.commit();
} finally {
writer.close();
}
}
/**
* 创建索引
*
* @param vo
*/
public void writeIndex(GoodsLuceneVo vo) {
IndexWriter writer = null;
try {
writer = openIndexWriter();
Document document = builderDocument(vo);
writer.addDocument(document);
// writer.optimize();
} catch (IOException e1) {
e1.printStackTrace();
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
writer.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 更新索引
*
* @param id
* @param vo
*/
public void update(String id, GoodsLuceneVo vo) {
try {
index_file = new File(index_path);
Directory directory = FSDirectory.open(index_file);
IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
IndexWriter writer = new IndexWriter(directory, writerConfig);
Document doc = builderDocument(vo);
Term term = new Term(GoodsLuceneVo.ID, String.valueOf(id));
writer.updateDocument(term, doc);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除文档
*
* @param id
*/
public void delete_index(String id) {
try {
index_file = new File(index_path);
Directory directory = FSDirectory.open(index_file);
IndexWriterConfig writerConfig = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
IndexWriter writer = new IndexWriter(directory, writerConfig);
Term term = new Term(GoodsLuceneVo.ID, String.valueOf(id));
writer.deleteDocuments(term);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除所有索引
*
* @param isdeletefile
* 是否删除文件
*/
public void deleteAllIndex(boolean isdeletefile) {
IndexWriter indexWriter = null;
index_file = new File(index_path);
if ((index_file.exists()) && (index_file.isDirectory())) {
try {
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
indexWriter = new IndexWriter(FSDirectory.open(index_file), iwc);
indexWriter.deleteAll();
} catch (Exception ex) {
ex.printStackTrace();
if (indexWriter != null)
try {
indexWriter.close();
} catch (IOException localIOException) {
}
} finally {
if (indexWriter != null)
try {
indexWriter.close();
} catch (IOException localIOException1) {
}
}
if (isdeletefile) {
deleteAllFile();
}
}
}
/**
* 删除索引文件
*/
private void deleteAllFile() {
index_file = new File(index_path);
File[] files = index_file.listFiles();
for (int i = 0; i < files.length; i++)
files[i].delete();
}
/**
* 打开indexwriter
*
* @return
* @throws IOException
*/
private IndexWriter openIndexWriter() throws IOException {
IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
index_file = new File(index_path);
indexWriterConfig.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
IndexWriter writer = new IndexWriter(FSDirectory.open(index_file), indexWriterConfig);
return writer;
}
/**
* 组件document
*
* @param goodsLuceneVo
* @return
*/
private Document builderDocument(GoodsLuceneVo goodsLuceneVo) {
Document document = new Document();
Field id = new LongField(GoodsLuceneVo.ID, goodsLuceneVo.getVo_id(), Store.YES);
//jsoup.clean 去掉里边的HTML代码
Field title = new TextField(GoodsLuceneVo.TITLE, Jsoup.clean(goodsLuceneVo.getVo_title(), Whitelist.none()), Store.YES);
Field content = new TextField(GoodsLuceneVo.CONTENT, Jsoup.clean(goodsLuceneVo.getVo_content(), Whitelist.none()),
Store.YES);
Field type = new StringField(GoodsLuceneVo.TYPE, goodsLuceneVo.getVo_type(), Store.YES);
Field store_price = new DoubleField(GoodsLuceneVo.STORE_PRICE, goodsLuceneVo.getVo_store_price(), Store.YES);
Field add_time = new LongField(GoodsLuceneVo.ADD_TIME, goodsLuceneVo.getVo_add_time(), Store.YES);
Field goods_salenum = new IntField(GoodsLuceneVo.GOODS_SALENUM, goodsLuceneVo.getVo_goods_salenum(), Store.YES);
document.add(id);
document.add(title);
document.add(content);
document.add(type);
document.add(store_price);
document.add(add_time);
document.add(goods_salenum);
return document;
}
/**
* 组件vo,包括高亮
*
* @param doc
* @param query
* @param vo
* @throws Exception
*/
private void builderVo(Document doc, Query query, GoodsLuceneVo vo) throws Exception {
SimpleHTMLFormatter simpleHTMLFormatter = new SimpleHTMLFormatter(prefixHTML, suffixHTML);
Highlighter highlighter = new Highlighter(simpleHTMLFormatter, new QueryScorer(query));
highlighter.setTextFragmenter(new SimpleFragmenter(this.textmaxlength));
String content = highlighter.getBestFragment(analyzer, GoodsLuceneVo.CONTENT, doc.get(GoodsLuceneVo.CONTENT));
String title = highlighter.getBestFragment(analyzer, GoodsLuceneVo.TITLE, doc.get(GoodsLuceneVo.TITLE));
if (content == null)
vo.setVo_content(doc.get(GoodsLuceneVo.CONTENT));
else {
vo.setVo_content(content);
}
if (title == null) {
vo.setVo_title(doc.get(GoodsLuceneVo.TITLE));
} else {
vo.setVo_title(title);
}
vo.setVo_id(Long.valueOf(doc.get(GoodsLuceneVo.ID)));
vo.setVo_url(doc.get(GoodsLuceneVo.URL));
vo.setVo_add_time(Long.valueOf(doc.get(GoodsLuceneVo.ADD_TIME)));
vo.setVo_store_price(Double.valueOf(doc.get(GoodsLuceneVo.STORE_PRICE)));
}
/**
* 组件volist
*
* @param documents
* @param query
* @return
*/
private List<GoodsLuceneVo> builderVoList(List<Document> documents, Query query) {
List<GoodsLuceneVo> goodsVoList = new ArrayList<GoodsLuceneVo>();
try {
for (Document document : documents) {
GoodsLuceneVo vo = new GoodsLuceneVo();
builderVo(document, query, vo);
goodsVoList.add(vo);
}
} catch (Exception e) {
e.printStackTrace();
}
return goodsVoList;
}
/**
* 商品参数组装
*
* @param params
* @param begin_price
* @param end_price
* @return
*/
private String goodsBuilderParams(String params, double begin_price, double end_price) {
if (params.indexOf(GoodsLuceneVo.TITLE + ":") < 0) {
params = "(" + GoodsLuceneVo.TITLE + ":" + params + " OR " + GoodsLuceneVo.CONTENT + ":" + params + ")";
}
if ((begin_price >= 0.0D) && (end_price > 0.0D)) {
params = params + " AND" + GoodsLuceneVo.STORE_PRICE + ":[" + begin_price + " TO " + end_price + "]";
}
return params;
}
/**
* @Title: searchTotalRecord
* @Description: 获取符合条件的总记录数
* @param query
* @return
* @throws IOException
*/
public static int searchTotalRecord(IndexSearcher searcher, Query query) throws IOException {
TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
if (topDocs == null || topDocs.scoreDocs == null || topDocs.scoreDocs.length == 0) {
return 0;
}
// ScoreDoc[] docs = topDocs.scoreDocs;
return topDocs.totalHits;
}
/**
* 根据页码和分页大小获取上一次的最后一个ScoreDoc 获取这个scoreDoc的时候,如果有排序,一定加上排序(sort) 否则会出现ScoreDoc 无法转换FieldDoc的错误
*/
private static ScoreDoc getLastScoreDoc(int pageIndex, int pageSize, Query query, IndexSearcher searcher, Sort sort)
throws IOException {
if (pageIndex == 1)
return null;// 如果是第一页就返回空
int num = pageSize * (pageIndex - 1);// 获取上一页的数量
TopDocs tds = searcher.search(query, num, sort);
return tds.scoreDocs[num - 1];
}
}
package com.gaibuy.foundation.lucene;
public class StoreLuceneVo {
public static final String STORE_ID = "store_id";
public static final String STORE_ADD_TIME = "store_add_time";
public static final String STORE_TITLE = "store_title";
public static final String STORE_CLASS = "store_class";
public static final String STORE_CONTENT = "store_content";
public static final String STORE_RECOMMEND = "store_recommend";
public static final String STORE_AREA_TYPE = "store_area_type";
public static final String CARD_APPROVE = "card_approve";
public static final String REALSTORE_APPROVE = "realstore_approve";
public static final String STORE_FAVORITE_COUNT = "store_favorite_count";
public static final String STORE_CREDIT = "store_credit";
public static final String STORE_GRADE = "store_grade";
public static final String STORE_POINT = "store_point";
public static final String STORE_AREA = "store_area";
private Long store_id;
private int store_area_type;
private String store_title;
private String store_content;
private Long store_add_time;
/** 推荐 */
private String store_recommend;
/** 实名认证 */
private String card_approve;
/** 实体店认证 */
private String realstore_approve;
/** 收藏数量 */
private int store_favorite_count;
/** 店铺信用 */
private int store_credit;
/** 级别 */
private int store_grade;
/** 好评率 */
private Double store_point;
/** 地区 */
private Long store_area;
/** 分类 */
private Long store_class;
public Long getStore_id() {
return store_id;
}
public void setStore_id(Long store_id) {
this.store_id = store_id;
}
public int getStore_area_type() {
return store_area_type;
}
public void setStore_area_type(int store_area_type) {
this.store_area_type = store_area_type;
}
public String getStore_title() {
return store_title;
}
public void setStore_title(String store_title) {
this.store_title = store_title;
}
public String getStore_content() {
return store_content;
}
public void setStore_content(String store_content) {
this.store_content = store_content;
}
public Long getStore_add_time() {
return store_add_time;
}
public void setStore_add_time(Long store_add_time) {
this.store_add_time = store_add_time;
}
public String getStore_recommend() {
return store_recommend;
}
public void setStore_recommend(String store_recommend) {
this.store_recommend = store_recommend;
}
public String getCard_approve() {
return card_approve;
}
public void setCard_approve(String card_approve) {
this.card_approve = card_approve;
}
public String getRealstore_approve() {
return realstore_approve;
}
public void setRealstore_approve(String realstore_approve) {
this.realstore_approve = realstore_approve;
}
public int getStore_favorite_count() {
return store_favorite_count;
}
public void setStore_favorite_count(int store_favorite_count) {
this.store_favorite_count = store_favorite_count;
}
public int getStore_credit() {
return store_credit;
}
public void setStore_credit(int store_credit) {
this.store_credit = store_credit;
}
public int getStore_grade() {
return store_grade;
}
public void setStore_grade(int store_grade) {
this.store_grade = store_grade;
}
public Double getStore_point() {
return store_point;
}
public void setStore_point(Double store_point) {
this.store_point = store_point;
}
public Long getStore_area() {
return store_area;
}
public void setStore_area(Long store_area) {
this.store_area = store_area;
}
public Long getStore_class() {
return store_class;
}
public void setStore_class(Long store_class) {
this.store_class = store_class;
}
}
package com.gaibuy.foundation.lucene;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.document.Document;
public class LuceneResult {
private List<Document> doc_list = new ArrayList<Document>();
private List<GoodsLuceneVo> goodsVo_list = new ArrayList<GoodsLuceneVo>();
private List<StoreLuceneVo> storeVo_list = new ArrayList<StoreLuceneVo>();
private int pages;
private int rows;
private int currentPage;
private int pageSize = 10;
public LuceneResult(int currentPage, int pageSize) {
this.currentPage = currentPage;
this.pageSize = pageSize;
}
public List<GoodsLuceneVo> getGoodsVo_list() {
return goodsVo_list;
}
public void setGoodsVo_list(List<GoodsLuceneVo> goodsVo_list) {
this.goodsVo_list = goodsVo_list;
}
public List<StoreLuceneVo> getStoreVo_list() {
return storeVo_list;
}
public void setStoreVo_list(List<StoreLuceneVo> storeVo_list) {
this.storeVo_list = storeVo_list;
}
public List<Document> getDoc_list() {
return doc_list;
}
public void setDoc_list(List<Document> doc_list) {
this.doc_list = doc_list;
}
public int getPages() {
int totalRecord = getRows();
if (totalRecord == 0) {
pages = 0;
} else {
int pageSize = getPageSize();
pages = totalRecord % pageSize == 0 ? totalRecord / pageSize : (totalRecord / pageSize) + 1;
}
return this.pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public int getRows() {
return this.rows;
}
public void setRows(int rows) {
this.rows = rows;
pages = rows / pageSize;
}
public int getCurrentPage() {
if (currentPage <= 0) {
currentPage = 1;
} else {
int totalPage = getPages();
if (totalPage > 0 && currentPage > totalPage) {
currentPage = totalPage;
}
}
return this.currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPageSize() {
if (pageSize <= 0) {
pageSize = 10;
}
return this.pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
}