Lucene 示例

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


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值