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; } }