package zwdt.action.web;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import net.paoding.analysis.analyzer.PaodingAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.DuplicateFilter;
import org.apache.lucene.search.Filter;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.NumericRangeFilter;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
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 pt.pojo.xtgl.SysArea;
import pt.service.xtgl.ISysAreaService;
import pt.vo.SearchPagination;
import pt.vo.SearchResultBean;
import util.BaseParameter;
import util.Common;
import util.base.BaseAction;
import util.lucene.LuceneUtil;
import zwdt.service.IServiceBaseService;
/**
* 页面用户搜索action
* @author liulx
* @version v1.0 2014-10-14
*/
public class StationSearchAction extends BaseAction {
private static final long serialVersionUID = 1L;
/** 用户页面搜索内容 */
private String paramValue;
/** 用户页面搜索内容,jquery.autocomplet 插件的默认查询参数是 q。 */
private String q;
/** 用户页面搜索的时间范围 */
private String date;
/** 用户页面搜索的查询范围 */
private String pos;
/** 用户页面搜索的相关度查询条件 */
private String od;
/** 分类检索 */
private String category;
/** 查询结果总条数 */
private Long total;
/** 查询用时,单位是秒 */
private Long cost;
/** 个人办事查询总条数 */
private Long gerenBanShiTotal;
/** 便民服务查询总条数 */
private Long bianMinFuWuTotal;
/** 分页搜索时跳转到第多少页 */
private String jumpPage;
private String p;
private List<SearchResultBean> searchResultList;
private IServiceBaseService serviceBaseService;
private ISysAreaService sysAreaService;
/** 分页 */
private SearchPagination searchPagination;
/** 区划id */
private String districtId;
/** 区划名称 */
private String districtName;
/** 站点id */
private String webid;
/**
* 全站搜索
* @author liulx
* @date 2014-10-14
* @return
*/
public String stationSearch() {
getSelectedDistrictId();
if (Common.isNullOrSpace(q)) {
gerenBanShiTotal = 0L;
bianMinFuWuTotal = 0L;
return SUCCESS;
}
Long startTime = System.currentTimeMillis();
if (Common.isNullOrSpace(category) || category.equals(BaseParameter.LUCENE_SEARCH_CATEGORY_GE_REN_BAN_SHI)) {
try {
getBianMinSearchResult();
} catch (Exception e) {
error(null, e);
}
try {
getGeRenSearchResult();
} catch (Exception e) {
error(null, e);
}
} else if (category.equals(BaseParameter.LUCENE_SEARCH_CATEGORY_BIAN_MING_FUWU)) {
try {
getGeRenSearchResult();
} catch (Exception e) {
error(null, e);
}
try {
getBianMinSearchResult();
} catch (Exception e) {
error(null, e);
}
}
if (gerenBanShiTotal == null) {
gerenBanShiTotal = 0L;
}
if (bianMinFuWuTotal == null) {
bianMinFuWuTotal = 0L;
}
cost = (System.currentTimeMillis() - startTime) / 1000;
return SUCCESS;
}
/**
* 返回查询关键字相关的查询条件
* @author liulx
* @date 2014-10-14
* @return
*/
public void getSearchParamTips() {
// 返回json格式示例如下:
// {"suggestions":["<em>结婚登记</em>","内地居民与外国人<em>结婚登记</em>","双方为非内地居民<em>结婚登记</em>","涉及外国人、港、澳、台居民、华侨的<em>结婚登记</em>","内地居民与港、澳、台居民<em>结婚登记</em>","内地居民与华侨、出国人员<em>结婚登记</em>","涉港澳台居民及华侨、外国人的<em>结婚登记</em>","补办<em>结婚登记</em>","办理<em>结婚登记</em>","国内公民<em>结婚登记</em>"]}
paramValue = q;
/*if (!Common.isNullOrSpace(q)) {
try {
q = new String(q.getBytes(), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}*/
if (Common.isNullOrSpace(q)) {
try {
String json = "{\"suggestions\":[]}";
returnAjaxInfo(json);
return;
} catch (Exception e) {
error(null, e);
}
}
IndexReader indexReader = null;
List<String> tipList = new ArrayList<String>();
try {
// 1. 创建 Directory
Directory dir = FSDirectory.open(new File(LuceneUtil.getIndexPosition() + "/ge_ren"));
// 2. 创建 IndexReader
indexReader = IndexReader.open(dir);
// 3. 创建 IndexSearch
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 4. 创建搜索的Query
// 创建parse确定搜索的内容,第二个参数为搜索的fiel
//Analyzer analyzer = new PaodingAnalyzer("e:/test/paoding-dic-home.properties");
Analyzer analyzer = new PaodingAnalyzer();
// QueryParser queryParser = new QueryParser(Version.LUCENE_36, "serviceName", new StandardAnalyzer(Version.LUCENE_36));
QueryParser queryParser = new QueryParser(Version.LUCENE_36, "serviceName", analyzer);
// 创建Query,表示搜索域中的内容
Query query = queryParser.parse(q);
// 查询结果去重
DuplicateFilter duplicateFilter = new DuplicateFilter("serviceName");
// 5. 搜索并返回 TopDocs
TopDocs topDocs = indexSearcher.search(query, duplicateFilter, 10);
// 6. 根据topDocs 获得 scoreDocs
ScoreDoc[] socreDocs = topDocs.scoreDocs;
SimpleHTMLFormatter htmlFormatter = new SimpleHTMLFormatter("<em>", "</em>");
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
highlighter.setTextFragmenter(new SimpleFragmenter(100));
String serviceName;
for (ScoreDoc doc : socreDocs) {
// 获取Document对象
Document document = indexSearcher.doc(doc.doc);
serviceName = document.get("serviceName");
serviceName = highlighter.getBestFragment(analyzer,"serviceName",serviceName) == null ? serviceName : highlighter.getBestFragment(analyzer,"serviceName",serviceName);
// 根据Document对象获取需要的值
if (!Common.isNullOrSpace(serviceName) && serviceName.length() > 51) {
serviceName = serviceName.substring(0, 49) + "...";
}
tipList.add(serviceName);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (indexReader != null) {
try {
indexReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
StringBuilder sb = new StringBuilder("");
try {
sb.append("{\"suggestions\":[");
if (tipList.size() > 0) {
int count = 0;
for (String str : tipList) {
sb.append("\"" + str.replaceFirst(q, "<em>" + q + "</em>") + "\"");
if (++count < tipList.size()) {
sb.append(",");
}
}
}
sb.append("]}");
returnAjaxInfo(sb.toString());
} catch (Exception e) {
error(null, e);
}
}
/**
* 返回个人办事查询结果
* @author liulx
* @date 2014-10-14
* @return
*/
@SuppressWarnings("static-access")
private List<SearchResultBean> getGeRenSearchResult() {
// 返回json格式示例如下:
// {"suggestions":["<em>结婚登记</em>","内地居民与外国人<em>结婚登记</em>","双方为非内地居民<em>结婚登记</em>","涉及外国人、港、澳、台居民、华侨的<em>结婚登记</em>","内地居民与港、澳、台居民<em>结婚登记</em>","内地居民与华侨、出国人员<em>结婚登记</em>","涉港澳台居民及华侨、外国人的<em>结婚登记</em>","补办<em>结婚登记</em>","办理<em>结婚登记</em>","国内公民<em>结婚登记</em>"]}
if (Common.isNullOrSpace(q)) {
return null;
}
IndexReader indexReader = null;
try {
// 1. 创建 Directory
Directory dir = FSDirectory.open(new File(LuceneUtil.getIndexPosition() + BaseParameter.LUCENE_INDEX_DIR_GE_REN));
// 2. 创建 IndexReader
indexReader = IndexReader.open(dir);
// 3. 创建 IndexSearch
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 4. 创建搜索的Query
// 创建parse确定搜索的内容,第二个参数为搜索的fiel
//Analyzer analyzer = new PaodingAnalyzer("e:/test/paoding-dic-home.properties");
Analyzer analyzer = new PaodingAnalyzer();
// QueryParser queryParser = new QueryParser(Version.LUCENE_36, "serviceName", new StandardAnalyzer(Version.LUCENE_36));
// 多条件查询
//QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{"title","content"}, analyzer,null);
QueryParser queryParser = null;
MultiFieldQueryParser multiFieldQueryParser = null;
Query query = null;
if (BaseParameter.LUCENE_SEARCH_POS_TITLE.equals(pos)) { // 根据标题查询
//queryParser = new QueryParser(Version.LUCENE_36, "serviceName", analyzer);
BooleanClause.Occur[] flags=new BooleanClause.Occur[]{BooleanClause.Occur.MUST,BooleanClause.Occur.MUST};
multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_36, new String[]{"serviceName","areaId"}, analyzer, null);
query = multiFieldQueryParser.parse(Version.LUCENE_36, new String[]{q, districtId}, new String[]{"serviceName","areaId"}, flags, analyzer);
} else if (BaseParameter.LUCENE_SEARCH_POS_CONTENT.equals(pos)) { // 根据内容查询
//queryParser = new QueryParser(Version.LUCENE_36, "serviceClassifyName", analyzer);
BooleanClause.Occur[] flags=new BooleanClause.Occur[]{BooleanClause.Occur.MUST,BooleanClause.Occur.MUST};
multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_36, new String[]{"serviceClassifyName","areaId"}, analyzer, null);
query = multiFieldQueryParser.parse(Version.LUCENE_36, new String[]{q, districtId}, new String[]{"serviceClassifyName","areaId"}, flags, analyzer);
} else { // 全部查询 实现 A and (B or C)
BooleanQuery mainQuery = new BooleanQuery();
TermQuery contentFilter = new TermQuery(new Term("areaId", districtId));
mainQuery.add(contentFilter, BooleanClause.Occur.MUST);
BooleanQuery idFilter = new BooleanQuery();
idFilter.setMinimumNumberShouldMatch(1);
idFilter.add(new TermQuery(new Term("serviceName", q)), BooleanClause.Occur.SHOULD);
idFilter.add(new TermQuery(new Term("serviceClassifyName", q)), BooleanClause.Occur.SHOULD);
mainQuery.add(idFilter, BooleanClause.Occur.MUST);
query = mainQuery;
}
// 创建Query,表示搜索域中的内容
if (query == null) {
query = queryParser.parse(q);
}
// 以下是相关度排序,lucene 默认的排序方式是相关度排序
Sort sort = null;
if (!Common.isNullOrSpace(od) && od.equals(BaseParameter.LUCENE_SEARCH_SORT_TIME)) {
// 以下这行代码意味着 先用相关度排序,再按照时间排序(也就是说:在相关度相同的情况下,按照时间排序)
//sort = new Sort(SortField.FIELD_SCORE, new SortField("createDate", SortField.LONG, false));
sort = new Sort(new SortField("createDate", SortField.LONG, true)); // false 为升序、true 为降序,当内部 score 相同时,按照索引序列排序
// 默认情况下,索引小的排在前面。如果 把构造函数中的 reverse 参数设置为true,则索引大的排序在前面。
} else { // 如果是相关度排序且用户在子站,
if (sysAreaService.querySysAreaListByTopId(districtId) == null || sysAreaService.querySysAreaListByTopId(districtId).size() == 0)
sort = new Sort(SortField.FIELD_SCORE, new SortField("areaId", SortField.STRING, false));
}
Filter filter = null;
if (!BaseParameter.NO.equals(date) && !Common.isNullOrSpace(date)) {
filter = NumericRangeFilter.newLongRange("createDate", getMinLong(), new Date().getTime(), Boolean.TRUE, Boolean.TRUE);
}
// 5. 搜索并返回 TopDocs // 注意此处的 Integer.MAX_VALUE
TopDocs topDocs;
if (sort != null) {
topDocs = indexSearcher.search(query, filter, Integer.MAX_VALUE, sort);
} else {
topDocs = indexSearcher.search(query, filter, Integer.MAX_VALUE);
}
// 分页
resetPageration();
if (searchPagination.getMaxRowCount() == null) {
searchPagination.setMaxRowCount((long)topDocs.totalHits);
}
this.total = searchPagination.getMaxRowCount();
gerenBanShiTotal = this.total;
int pageCount = 0; // 页数
if (total % searchPagination.getRowsPerPage() == 0) {
pageCount = (int) (total / searchPagination.getRowsPerPage());
} else {
pageCount = (int) (total / searchPagination.getRowsPerPage()) + 1;
}
searchPagination.setMaxPage(pageCount);
jumpPage = p;
// 设置当前页
if (Common.isNullOrSpace(jumpPage)) {
jumpPage = "1";
}
searchPagination.setCurPage(Integer.parseInt(jumpPage));
//计算firstResult
int firstResult = (searchPagination.getCurPage() - 1) * searchPagination.getRowsPerPage() + 1;
//计算从当前条数算还有多少条记录
long left = searchPagination.getMaxRowCount() - firstResult;
int maxResult = -1;
//如果剩余的记录数不如每页显示数,就设置maxResult为剩余条数
if(left < searchPagination.getRowsPerPage()) {
maxResult = Integer.valueOf(left + "") + 1;
//如果剩余记录数大于每页显示页数,就设置maxResult为每页条数
}else {
maxResult = searchPagination.getRowsPerPage();
}
// 根据 Lucene官方说明:Lucene分页的实现方式是先取出所有的搜索结果,再找到需要的数据。其理由是搜索速度已经非常的
// 快,不需要想 sql 那样分页。
// 6. 根据topDocs 获得 scoreDocs
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
searchResultList = new ArrayList<SearchResultBean>();
SearchResultBean resultBean;
Document document;
String title; // 标题
String summary; // 摘要
ScoreDoc doc;
SimpleHTMLFormatter htmlFormatter = new SimpleHTMLFormatter("<em>", "</em>");
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
highlighter.setTextFragmenter(new SimpleFragmenter(100));
for (int i = firstResult - 1; i < firstResult + maxResult - 1; i++) {
doc = scoreDocs[i];
// 获取Document对象
document = indexSearcher.doc(doc.doc);
// 根据Document对象获取需要的值
title = document.get("serviceName");
summary = document.get("serviceClassifyName");
if (BaseParameter.LUCENE_SEARCH_POS_ALL.equals(pos)) {
title = highlighter.getBestFragment(analyzer,"serviceName",title) == null ? title : highlighter.getBestFragment(analyzer,"serviceName",title);
summary = highlighter.getBestFragment(analyzer,"serviceClassifyName",summary) == null ? summary : highlighter.getBestFragment(analyzer,"serviceClassifyName",summary);
} else if (BaseParameter.LUCENE_SEARCH_POS_TITLE.equals(pos)) {
title = highlighter.getBestFragment(analyzer,"serviceName",title) == null ? title : highlighter.getBestFragment(analyzer,"serviceName",title);
} else if (BaseParameter.LUCENE_SEARCH_POS_CONTENT.equals(pos)) {
summary = highlighter.getBestFragment(analyzer,"serviceClassifyName",summary) == null ? summary : highlighter.getBestFragment(analyzer,"serviceClassifyName",summary);
} else {
title = highlighter.getBestFragment(analyzer,"serviceName",title) == null ? title : highlighter.getBestFragment(analyzer,"serviceName",title);
summary = highlighter.getBestFragment(analyzer,"serviceClassifyName",summary) == null ? summary : highlighter.getBestFragment(analyzer,"serviceClassifyName",summary);
}
resultBean = new SearchResultBean();
resultBean.setTitle(title);
if (!Common.isNullOrSpace(summary) && summary.length() > 150) {
summary = summary.substring(0, 150);
}
resultBean.setSummary(summary);
resultBean.setDate(document.get("createDate"));
resultBean.setUrlLink("http://localhost:8080/zwdt/stationSearch.action");
searchResultList.add(resultBean);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (indexReader != null) {
try {
indexReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return searchResultList;
}
/**
* 返回便民服务查询结果
* @author liulx
* @date 2014-10-14
* @return
*/
@SuppressWarnings("static-access")
private List<SearchResultBean> getBianMinSearchResult() {
// 返回json格式示例如下:
// {"suggestions":["<em>结婚登记</em>","内地居民与外国人<em>结婚登记</em>","双方为非内地居民<em>结婚登记</em>","涉及外国人、港、澳、台居民、华侨的<em>结婚登记</em>","内地居民与港、澳、台居民<em>结婚登记</em>","内地居民与华侨、出国人员<em>结婚登记</em>","涉港澳台居民及华侨、外国人的<em>结婚登记</em>","补办<em>结婚登记</em>","办理<em>结婚登记</em>","国内公民<em>结婚登记</em>"]}
if (Common.isNullOrSpace(q)) {
return null;
}
IndexReader indexReader = null;
try {
// 1. 创建 Directory
Directory dir = FSDirectory.open(new File(LuceneUtil.getIndexPosition() + BaseParameter.LUCENE_INDEX_DIR_BIAN_MIN));
// 2. 创建 IndexReader
indexReader = IndexReader.open(dir);
// 3. 创建 IndexSearch
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// 4. 创建搜索的Query
// 创建parse确定搜索的内容,第二个参数为搜索的fiel
//Analyzer analyzer = new PaodingAnalyzer("e:/test/paoding-dic-home.properties");
Analyzer analyzer = new PaodingAnalyzer();
// QueryParser queryParser = new QueryParser(Version.LUCENE_36, "serviceName", new StandardAnalyzer(Version.LUCENE_36));
// 多条件查询
//QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_CURRENT, new String[]{"title","content"}, analyzer,null);
QueryParser queryParser = null;
MultiFieldQueryParser multiFieldQueryParser = null;
Query query = null;
if (BaseParameter.LUCENE_SEARCH_POS_TITLE.equals(pos)) {
//queryParser = new QueryParser(Version.LUCENE_36, "contentMainTitle", analyzer); // 根据标题查询
BooleanClause.Occur[] flags=new BooleanClause.Occur[]{BooleanClause.Occur.MUST,BooleanClause.Occur.MUST};
multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_36, new String[]{"contentMainTitle","areaId"}, analyzer, null);
query = multiFieldQueryParser.parse(Version.LUCENE_36, new String[]{q, districtId}, new String[]{"contentMainTitle","areaId"}, flags, analyzer);
} else if (BaseParameter.LUCENE_SEARCH_POS_CONTENT.equals(pos)) { // 根据内容查询
//queryParser = new QueryParser(Version.LUCENE_36, "content", analyzer);
BooleanClause.Occur[] flags=new BooleanClause.Occur[]{BooleanClause.Occur.MUST,BooleanClause.Occur.MUST};
multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_36, new String[]{"content","areaId"}, analyzer, null);
query = multiFieldQueryParser.parse(Version.LUCENE_36, new String[]{q, districtId}, new String[]{"content","areaId"}, flags, analyzer);
} else { // 全部查询 实现 A and (B or C)
/*BooleanClause.Occur[] flags=new BooleanClause.Occur[]{BooleanClause.Occur.MUST, BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST};
multiFieldQueryParser = new MultiFieldQueryParser(Version.LUCENE_36, new String[]{"areaId", "contentMainTitle","content"}, analyzer, null);
query = multiFieldQueryParser.parse(Version.LUCENE_36, new String[]{districtId, q, q}, new String[]{"areaId", "contentMainTitle","content"}, flags, analyzer);*/
BooleanQuery mainQuery = new BooleanQuery();
TermQuery contentFilter = new TermQuery(new Term("areaId", districtId));
mainQuery.add(contentFilter, BooleanClause.Occur.MUST);
BooleanQuery idFilter = new BooleanQuery();
idFilter.setMinimumNumberShouldMatch(1);
idFilter.add(new TermQuery(new Term("contentMainTitle", q)), BooleanClause.Occur.SHOULD);
idFilter.add(new TermQuery(new Term("content", q)), BooleanClause.Occur.SHOULD);
mainQuery.add(idFilter, BooleanClause.Occur.MUST);
query = mainQuery;
}
// 创建Query,表示搜索域中的内容
if (query == null) {
query = queryParser.parse(q);
}
// 以下是相关度排序,lucene 默认的排序方式是相关度排序
Sort sort = null;
if (!Common.isNullOrSpace(od) && od.equals(BaseParameter.LUCENE_SEARCH_SORT_TIME)) {
// 以下这行代码意味着 先用相关度排序,再按照时间排序(也就是说:在相关度相同的情况下,按照时间排序)
//sort = new Sort(SortField.FIELD_SCORE, new SortField("createDate", SortField.LONG, false));
sort = new Sort(new SortField("issurDate", SortField.LONG, true)); // false 为升序、true 为降序
}
Filter filter = null;
if (!BaseParameter.NO.equals(date) && !Common.isNullOrSpace(date)) {
filter = NumericRangeFilter.newLongRange("issurDate", getMinLong(), new Date().getTime(), Boolean.TRUE, Boolean.TRUE);
}
// 5. 搜索并返回 TopDocs // 注意此处的 Integer.MAX_VALUE
TopDocs topDocs;
if (sort != null) {
topDocs = indexSearcher.search(query, filter, Integer.MAX_VALUE, sort);
} else {
topDocs = indexSearcher.search(query, filter, Integer.MAX_VALUE);
}
// 分页
resetPageration();
if (searchPagination.getMaxRowCount() == null) {
searchPagination.setMaxRowCount((long)topDocs.totalHits);
}
this.total = searchPagination.getMaxRowCount();
bianMinFuWuTotal = this.total;
int pageCount = 0; // 页数
if (total % searchPagination.getRowsPerPage() == 0) {
pageCount = (int) (total / searchPagination.getRowsPerPage());
} else {
pageCount = (int) (total / searchPagination.getRowsPerPage()) + 1;
}
searchPagination.setMaxPage(pageCount);
jumpPage = p;
// 设置当前页
if (Common.isNullOrSpace(jumpPage)) {
jumpPage = "1";
}
searchPagination.setCurPage(Integer.parseInt(jumpPage));
//计算firstResult
int firstResult = (searchPagination.getCurPage() - 1) * searchPagination.getRowsPerPage() + 1;
//计算从当前条数算还有多少条记录
long left = searchPagination.getMaxRowCount() - firstResult;
int maxResult = -1;
//如果剩余的记录数不如每页显示数,就设置maxResult为剩余条数
if(left < searchPagination.getRowsPerPage()) {
maxResult = Integer.valueOf(left + "");
//如果剩余记录数大于每页显示页数,就设置maxResult为每页条数
}else {
maxResult = searchPagination.getRowsPerPage();
}
// 根据 Lucene官方说明:Lucene分页的实现方式是先取出所有的搜索结果,再找到需要的数据。其理由是搜索速度已经非常的
// 快,不需要想 sql 那样分页。
// 6. 根据topDocs 获得 scoreDocs
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
searchResultList = new ArrayList<SearchResultBean>();
SearchResultBean resultBean;
Document document;
String title; // 标题
String summary; // 摘要
ScoreDoc doc;
SimpleHTMLFormatter htmlFormatter = new SimpleHTMLFormatter("<em>", "</em>");
Highlighter highlighter = new Highlighter(htmlFormatter, new QueryScorer(query));
highlighter.setTextFragmenter(new SimpleFragmenter(100));
for (int i = firstResult - 1; i < firstResult + maxResult; i++) {
doc = scoreDocs[i];
// 获取Document对象
document = indexSearcher.doc(doc.doc);
// 根据Document对象获取需要的值
title = document.get("contentMainTitle");
summary = document.get("content");
if (BaseParameter.LUCENE_SEARCH_POS_ALL.equals(pos)) {
title = highlighter.getBestFragment(analyzer,"contentMainTitle",title) == null ? title : highlighter.getBestFragment(analyzer,"contentMainTitle",title);
summary = highlighter.getBestFragment(analyzer,"content",summary) == null ? summary : highlighter.getBestFragment(analyzer,"content",summary);
} else if (BaseParameter.LUCENE_SEARCH_POS_TITLE.equals(pos)) {
title = highlighter.getBestFragment(analyzer,"contentMainTitle",title) == null ? title : highlighter.getBestFragment(analyzer,"contentMainTitle",title);
} else if (BaseParameter.LUCENE_SEARCH_POS_CONTENT.equals(pos)) {
summary = highlighter.getBestFragment(analyzer,"content",summary) == null ? summary : highlighter.getBestFragment(analyzer,"content",summary);
} else { // 默认按照标题范围查询
title = highlighter.getBestFragment(analyzer,"contentMainTitle",title) == null ? title : highlighter.getBestFragment(analyzer,"contentMainTitle",title);
}
resultBean = new SearchResultBean();
resultBean.setTitle(title);
if (!Common.isNullOrSpace(summary) && summary.length() > 150) {
summary = summary.substring(0, 150);
}
resultBean.setSummary(summary);
resultBean.setDate(document.get("issurDate"));
resultBean.setUrlLink("http://localhost:8080/zwdt/stationSearch.action");
searchResultList.add(resultBean);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (indexReader != null) {
try {
indexReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return searchResultList;
}
/**
* 获取用户当前选择站点
* @author liulx
* @date 2014-10-20
*/
public void getCurrentSearchSite() {
try {
//String json = "[{\"iid\":1,\"name\":\"浙江省\",\"logo\":\"\",\"parentId\":null,\"defaultSite\":true,\"orderId\":1,\"enableSmart\":true,\"token\":\"dchunter\"},{\"iid\":2,\"name\":\"杭州市\",\"logo\":\"\",\"parentId\":1,\"defaultSite\":false,\"orderId\":2,\"enableSmart\":false,\"token\":null}]";
String json = sysAreaService.getAllAreaJson();
returnAjaxInfo(json);
} catch (Exception e) {
error(null, e);
}
}
/**
* 生成索引
* @author liulx
* @date 2014-10-14
*/
public void generateIndex() {
LuceneUtil.generateIndex();
LuceneUtil.genConvenienceServiceIndex(); // 便民服务索引
LuceneUtil.genFAQsIndex(); // 常见问题
try {
returnAjaxInfo("索引建立成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
private Long getMinLong() {
String timeFrame = date;
Date date = null;
if (BaseParameter.LUCENE_SEARCH_DAY.equals(timeFrame)) {
date = util.DateTools.addDay(new Date(), -1);
} else if (BaseParameter.LUCENE_SEARCH_WEEK.equals(timeFrame)) {
date = util.DateTools.addDay(new Date(), -7);
} else if (BaseParameter.LUCENE_SEARCH_MONTH.equals(timeFrame)) {
int dateOfMonth = util.DateTools.getMonthOfDays(util.DateTools.addDay(new Date(), -1));
date = util.DateTools.addDay(new Date(), -dateOfMonth);
} else if (BaseParameter.LUCENE_SEARCH_YEAR.equals(timeFrame)) {
date = util.DateTools.addDay(new Date(), -365);
}
return date.getTime();
}
/**
* 重置分页内容
* @author liulx
* @date 2014-10-19
*/
private void resetPageration() {
int pageCount = searchPagination.getRowsPerPage();
//Long allCount = searchPagination.getMaxRowCount();
searchPagination = new SearchPagination();
searchPagination.setRowsPerPage(pageCount);
//searchPagination.setMaxRowCount(allCount);
}
/**
* 获取默认区域id
* @author liulx
* @date 2014-10-19
* @return
*/
private void getSelectedDistrictId() {
try {
SysArea area = null;
if (!Common.isNullOrSpace(districtId)) {
area = sysAreaService.getSysAreaBytopId(districtId);
if (area != null) {
districtName = area.getAreaName();
}
} else {
area = sysAreaService.getSysAreaTop();
if (area != null) {
districtId = area.getAreaId();
districtName = area.getAreaName();
}
}
} catch (Exception e) {
error(null, e);
}
}
/**
* @return the serviceBaseService
*/
public IServiceBaseService getServiceBaseService() {
return serviceBaseService;
}
/**
* @param serviceBaseService the serviceBaseService to set
*/
public void setServiceBaseService(IServiceBaseService serviceBaseService) {
this.serviceBaseService = serviceBaseService;
}
/**
* @return the 用户页面搜索内容
*/
public String getParamValue() {
return paramValue;
}
/**
* @param 用户页面搜索内容 the paramValue to set
*/
public void setParamValue(String paramValue) {
this.q = paramValue;
this.paramValue = paramValue;
}
/**
* @return the 用户页面搜索内容
*/
public String getQ() {
return q;
}
/**
* @param 用户页面搜索内容 the q to set
*/
public void setQ(String q) {
/*try {
this.q = new String(q.getBytes(), "utf-8");
} catch (UnsupportedEncodingException e) {
this.q = q;
}*/
this.q = q;
}
/**
* @return the 用户页面搜索的时间范围
*/
public String getDate() {
return date;
}
/**
* @param 用户页面搜索的时间范围 the date to set
*/
public void setDate(String date) {
this.date = date;
}
/**
* @return the 查询结果总条数
*/
public Long getTotal() {
return total;
}
/**
* @param 查询结果总条数 the total to set
*/
public void setTotal(Long total) {
this.total = total;
}
/**
* @return the 查询用时,单位是秒
*/
public Long getCost() {
return cost;
}
/**
* @param 查询用时,单位是秒 the cost to set
*/
public void setCost(Long cost) {
this.cost = cost;
}
/**
* @return the 用户页面搜索的查询范围
*/
public String getPos() {
return pos;
}
/**
* @param 用户页面搜索的查询范围 the pos to set
*/
public void setPos(String pos) {
this.pos = pos;
}
/**
* @return the 用户页面搜索的相关度查询条件
*/
public String getOd() {
return od;
}
/**
* @param 用户页面搜索的相关度查询条件 the od to set
*/
public void setOd(String od) {
this.od = od;
}
/**
* @return the searchResultList
*/
public List<SearchResultBean> getSearchResultList() {
return searchResultList;
}
/**
* @param searchResultList the searchResultList to set
*/
public void setSearchResultList(List<SearchResultBean> searchResultList) {
this.searchResultList = searchResultList;
}
/**
* @return the 分页
*/
public SearchPagination getSearchPagination() {
return searchPagination;
}
/**
* @param 分页 the searchPagination to set
*/
public void setSearchPagination(SearchPagination searchPagination) {
this.searchPagination = searchPagination;
}
/**
* @return the 分页搜索时跳转到第多少页
*/
public String getJumpPage() {
return jumpPage;
}
/**
* @param 分页搜索时跳转到第多少页 the jumpPage to set
*/
public void setJumpPage(String jumpPage) {
this.jumpPage = jumpPage;
}
/**
* @return the p
*/
public String getP() {
return p;
}
/**
* @param p the p to set
*/
public void setP(String p) {
this.p = p;
}
/**
* @return the 分类检索
*/
public String getCategory() {
return category;
}
/**
* @param 分类检索 the category to set
*/
public void setCategory(String category) {
this.category = category;
}
/**
* @return the 个人办事查询总条数
*/
public Long getGerenBanShiTotal() {
return gerenBanShiTotal;
}
/**
* @param 个人办事查询总条数 the gerenBanShiTotal to set
*/
public void setGerenBanShiTotal(Long gerenBanShiTotal) {
this.gerenBanShiTotal = gerenBanShiTotal;
}
/**
* @return the 便民服务查询总条数
*/
public Long getBianMinFuWuTotal() {
return bianMinFuWuTotal;
}
/**
* @param 便民服务查询总条数 the bianMinFuWuTotal to set
*/
public void setBianMinFuWuTotal(Long bianMinFuWuTotal) {
this.bianMinFuWuTotal = bianMinFuWuTotal;
}
/**
* @return the sysAreaService
*/
public ISysAreaService getSysAreaService() {
return sysAreaService;
}
/**
* @param sysAreaService the sysAreaService to set
*/
public void setSysAreaService(ISysAreaService sysAreaService) {
this.sysAreaService = sysAreaService;
}
/**
* @return the districtId
*/
public String getDistrictId() {
return districtId;
}
/**
* @param districtId the districtId to set
*/
public void setDistrictId(String districtId) {
this.districtId = districtId;
}
/**
* @return the 区划名称
*/
public String getDistrictName() {
return districtName;
}
/**
* @param 区划名称 the districtName to set
*/
public void setDistrictName(String districtName) {
this.districtName = districtName;
}
/**
* @return the 站点id
*/
public String getWebid() {
return webid;
}
/**
* @param 站点id the webid to set
*/
public void setWebid(String webid) {
this.districtId = webid;
this.webid = webid;
}
}
package util.lucene;
import java.io.File;
import java.io.IOException;
import java.util.List;
import net.paoding.analysis.analyzer.PaodingAnalyzer;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.NumericField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import util.BaseParameter;
import util.Common;
import zwdt.pojo.InfoTcontent;
import zwdt.pojo.ServiceBase;
import zwdt.service.IMlbzServiceQuestionService;
import zwdt.service.IServiceBaseService;
import zwdt.service.IinfoTcontentService;
/**
* Lucene 相关工具类
* @author liulx
* @version v1.0 2014-10-15
*/
public class LuceneUtil {
private static IServiceBaseService serviceBaseService = (IServiceBaseService)Common.getService("serviceBaseService");
/** 内容发布信息管理 */
private static IinfoTcontentService infoTcontentService = (IinfoTcontentService)Common.getService("infoTcontentService");
/**
* 生成个人办事索引
* @author liulx
* @date 2014-10-14
*/
public static void generateIndex() {
List<ServiceBase> serviceBaseList = null;
try {
serviceBaseList = serviceBaseService.getServiceBaseList(null);
} catch (Exception e1) {
e1.printStackTrace();
}
IndexWriter indexWriter = null;
try {
// 1. 创建 Directory (索引存放位置)
//Directory dir = new RAMDirectory();
Directory dir = FSDirectory.open(new File(getIndexPosition() + BaseParameter.LUCENE_INDEX_DIR_GE_REN));
Analyzer analyzer = new PaodingAnalyzer();
// 2. 创建IndexWriter 写索引
//Analyzer analyzer = new PaodingAnalyzer("e:/test/paoding-dic-home.properties");
//IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36));
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
indexWriter = new IndexWriter(dir, iwc);
// 3. 创建Document 对象 field
Document document;
for (ServiceBase serviceBase : serviceBaseList) {
document = new Document();
// 4. 为Documen添加field
document.add(new Field("serviceId", serviceBase.getServiceId(), Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("areaId", serviceBase.getAreaId(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("serviceName", serviceBase.getServiceName(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("serviceClassifyName", serviceBase.getSetAccording(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("caseTypeName", serviceBase.getCaseTypeName(), Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("ssjgmc", serviceBase.getSsjgmc(), Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("ssjgmc", serviceBase.getSsjgmc(), Field.Store.YES, Field.Index.NOT_ANALYZED));
//document.add(new Field("centerAcceptDate", DateTools.dateToString(serviceBase.getCreateDate(), DateTools.Resolution.DAY), Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new NumericField("createDate", Field.Store.YES, true).setLongValue(serviceBase.getCreateDate().getTime()));
// 5. 通过IndexWriter 添加文档到索引中
indexWriter.addDocument(document);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (indexWriter != null) {
try {
indexWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 创建便民服务索引
* @author liulx
* @date 2014-10-17
*/
public static void genConvenienceServiceIndex() {
List<InfoTcontent> infoTcontentList = null;
try {
infoTcontentList = infoTcontentService.getAllInfoTcontents();
} catch (Exception e1) {
e1.printStackTrace();
}
IndexWriter indexWriter = null;
try {
// 1. 创建 Directory (索引存放位置)
//Directory dir = new RAMDirectory();
Directory dir = FSDirectory.open(new File(getIndexPosition() + BaseParameter.LUCENE_INDEX_DIR_BIAN_MIN));
Analyzer analyzer = new PaodingAnalyzer();
// 2. 创建IndexWriter 写索引
//Analyzer analyzer = new PaodingAnalyzer("e:/test/paoding-dic-home.properties");
//IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36));
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
indexWriter = new IndexWriter(dir, iwc);
// 3. 创建Document 对象 field
Document document;
for (InfoTcontent content : infoTcontentList) {
document = new Document();
// 4. 为Documen添加field
document.add(new Field("contentId", content.getContentId(), Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("areaId", content.getAreaId(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("contentMainTitle", content.getContentMainTitle(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("content", content.getContent(), Field.Store.YES, Field.Index.ANALYZED));
document.add(new NumericField("issurDate", Field.Store.YES, true).setLongValue(content.getIssurDate().getTime()));
// 5. 通过IndexWriter 添加文档到索引中
indexWriter.addDocument(document);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (indexWriter != null) {
try {
indexWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 创建常见问题
* @date 2014-10-19
*/
@SuppressWarnings("unchecked")
public static void genFAQsIndex() {
IndexWriter indexWriter = null;
try {
IMlbzServiceQuestionService quesService = (IMlbzServiceQuestionService)Common.getService("mlbzServiceQuestionService");
List<Object[]> list = (List<Object[]>)quesService.getAllQuestionList();
// 1. 创建 Directory (索引存放位置)
//Directory dir = new RAMDirectory();
Directory dir = FSDirectory.open(new File(getIndexPosition() + BaseParameter.LUCENE_INDEX_DIR_FAQ));
Analyzer analyzer = new PaodingAnalyzer();
// 2. 创建IndexWriter 写索引
//Analyzer analyzer = new PaodingAnalyzer("e:/test/paoding-dic-home.properties");
//IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36));
IndexWriterConfig iwc = new IndexWriterConfig(Version.LUCENE_36, analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
indexWriter = new IndexWriter(dir, iwc);
// 3. 创建Document 对象 field
Document document;
for (Object[] obj : list) {
document = new Document();
// 4. 为Documen添加field
document.add(new Field("serviceName", obj == null ? "" : (String)obj[0], Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("ask", obj == null ? "" : (String)obj[1], Field.Store.YES, Field.Index.ANALYZED));
document.add(new Field("answer", obj == null ? "" : (String)obj[2], Field.Store.YES, Field.Index.ANALYZED));
// 5. 通过IndexWriter 添加文档到索引中
indexWriter.addDocument(document);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (indexWriter != null) {
try {
indexWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 获取索引存放位置
* @author liulx
* @date 2014-10-17
* @return
*/
public static String getIndexPosition() {
String indexPosition = BaseParameter.LUCENE_INDEX_POS;
if (Common.isNullOrSpace(indexPosition)) {
throw new RuntimeException("lucene 索引位置为空!");
} else if (indexPosition.contains(":")) {
return indexPosition;
} else {
System.out.println(LuceneUtil.class.getResource("/") + File.separator + indexPosition);
return LuceneUtil.class.getResource("/") + indexPosition;
}
}
}