全文检索扩展

作者:  最后修改:2013年10月18日  浏览数:504

注册全文检索类型

编写java类

  编写一个java类,实现IIndexType,这个类必须有以下几个方法:

/**

 * 获取索引字段

 */

public List<Field> getFields();

/**

 * 获取需要更新的检索类型内容总数量 

 * @param lastModifyTime 索引最后更新时间

 * @param params 检索内容参数

 * @return

 */

public int getModifiedTotal(Date lastModifyTime, Mapx<String, Object> params);

/**

 * 获取需要更新的检索类型分页内容

 */

public List<Document> getModifiedDocuments(Date lastModifyTime, Mapx<String, Object> params, int pageSize, int pageIndex);

/**

 * 获取需要删除的检索类型内容总数量 

 * @param lastModifyTime 索引最后更新时间

 * @return

 */

public int getDeletedTotal(Date lastModifyTime, Mapx<String, Object> params);

/**

 * 获取需要删除的检索类型分页内容 

 * @param lastModifyTime 索引最后更新时间

 * @param pageSize 分页大小

 * @param pageIndex 当前页数

 * @return

 */

  public List<Long> getDeletedIDs(Date lastModifyTime, Mapx<String, Object> params, int pageSize, int pageIndex);

  索引类型java类也可以直接继承AbstractIndexType抽象类,这个类的getFields()方法提供了检索比较通用的基础字段,如IndexType,Title,ID,_KeyWord,AddTime等。

  AbstractIndexType.java类代码完整示例如下:

package com.zving.search.service;

import java.util.ArrayList;

import java.util.List;

import org.apache.lucene.document.Field;

public abstract class AbstractIndexType implements IIndexType {

public List<Field> getFields() {

List<Field> list = new ArrayList<Field>();

list.add(new Field("INDEXTYPE""", Field.Store.YES, Field.Index.NOT_ANALYZED)); // 索引类型

list.add(new Field("TITLE""", Field.Store.YES, Field.Index.ANALYZED));

list.add(new Field("CONTENT""", Field.Store.YES, Field.Index.ANALYZED));

list.add(new Field("URL""", Field.Store.YES, Field.Index.NO)); // 可能需要处理

list.add(new Field("_KEYWORD""", Field.Store.NO, Field.Index.ANALYZED)); // 需要自定义内容,一般是Title+Content

list.add(new Field("ID""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("ADDTIME""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("MODIFYTIME""", Field.Store.YES, Field.Index.NOT_ANALYZED));

return list;

}

}

  完整的示例java类代码如下:

package com.zving.indextypetest.impl;

import java.util.ArrayList;

import java.util.Date;

import java.util.List;

import org.apache.lucene.document.Document;

import org.apache.lucene.document.Field;

import com.zving.contentcore.properties.impl.IndexEnable;

import com.zving.contentcore.util.CatalogUtil;

import com.zving.framework.collection.Mapx;

import com.zving.framework.data.DataRow;

import com.zving.framework.data.DataTable;

import com.zving.framework.data.Q;

import com.zving.framework.orm.DAO;

import com.zving.framework.orm.DAOSet;

import com.zving.framework.utility.DateUtil;

import com.zving.framework.utility.ObjectUtil;

import com.zving.framework.utility.StringUtil;

import com.zving.platform.code.YesOrNo;

import com.zving.schema.ZCCatalog;

import com.zving.schema.ZCComment;

import com.zving.search.service.IIndexType;

public class MyTestIndexType implements IIndexType {

public static final String ID = "CommentIndexType"// 评论索引类型

public String getID() {

return ID;

}

public String getName() {

return "评论索引类型";

}

public List<Field> getFields() {

List<Field> list = new ArrayList<Field>();

list.add(new Field("INDEXTYPE""", Field.Store.YES, Field.Index.NOT_ANALYZED)); // 索引类型

list.add(new Field("ID""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("TITLE""", Field.Store.YES, Field.Index.ANALYZED));

list.add(new Field("CONTENT""", Field.Store.YES, Field.Index.ANALYZED));

list.add(new Field("_KEYWORD""", Field.Store.NO, Field.Index.ANALYZED)); // 需要自定义内容,一般是Title+Content

list.add(new Field("SITEID""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("RELACONTENTID""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("CATALOGID""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("CATALOGNAME""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("CATALOGTYPE""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("CATALOGINNERCODE""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("VERIFYFLAG""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("VERIFYUSER""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("VERIFYTIME""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("INDEXENABLE""", Field.Store.YES, Field.Index.NOT_ANALYZED)); // 栏目配置:是否开启检索

list.add(new Field("ADDTIME""", Field.Store.YES, Field.Index.NOT_ANALYZED));

list.add(new Field("MODIFYTIME""", Field.Store.YES, Field.Index.NOT_ANALYZED));

return list;

}

public int getModifiedTotal(Date lastModifyTime, Mapx<String, Object> params) {

if (ObjectUtil.notEmpty(params.getDate("LastModifyTime"))) {

lastModifyTime = params.getDate("LastModifyTime");

}

Q qb = new Q("select count(*) from ZCComment where VerifyFlag=? and (ModifyTime>? or AddTime>?)", YesOrNo.Yes, lastModifyTime,

lastModifyTime);

if (ObjectUtil.notEmpty(params.getLong("SiteID"))) {

qb.append(" and SiteID=?", params.getLong("SiteID"));

}

if (ObjectUtil.notEmpty(params.getLong("CatalogID"))) {

qb.append(" and CatalogID=?", params.getLong("CatalogID"));

}

return qb.executeInt();

}

public List<Document> getModifiedDocuments(Date lastModifyTime, Mapx<String, Object> params, int pageSize, int pageIndex) {

if (ObjectUtil.notEmpty(params.getDate("LastModifyTime"))) {

lastModifyTime = params.getDate("LastModifyTime");

}

Q qb = new Q("where VerifyFlag=? and (ModifyTime>? or AddTime>?)", YesOrNo.Yes, lastModifyTime, lastModifyTime);

if (ObjectUtil.notEmpty(params.getLong("SiteID"))) {

qb.append(" and SiteID=?", params.getLong("SiteID"));

}

if (ObjectUtil.notEmpty(params.getLong("CatalogID"))) {

qb.append(" and CatalogID=?", params.getLong("CatalogID"));

}

DAOSet<ZCComment> set = new ZCComment().query(qb, pageSize, pageIndex);

return parseDocument(set);

}

public int getDeletedTotal(Date lastModifyTime, Mapx<String, Object> params) {

Q qb = new Q("select count(*) from BZCComment where BackupMemo=? and BackupTime>?", DAO.MEMO_DELETE, lastModifyTime);

if (ObjectUtil.notEmpty(params.getLong("SiteID"))) {

qb.append(" and SiteID=?", params.getLong("SiteID"));

}

if (ObjectUtil.notEmpty(params.getLong("CatalogID"))) {

qb.append(" and CatalogID=?", params.getLong("CatalogID"));

}

int count = qb.executeInt();

return count;

}

public List<Long> getDeletedIDs(Date lastModifyTime, Mapx<String, Object> params, int pageSize, int pageIndex) {

ArrayList<Long> list = new ArrayList<Long>();

Q qb = new Q("select ID from BZCComment where BackupMemo=? and BackupTime>?", DAO.MEMO_DELETE, lastModifyTime);

if (ObjectUtil.notEmpty(params.getLong("SiteID"))) {

qb.append(" and SiteID=?", params.getLong("SiteID"));

}

if (ObjectUtil.notEmpty(params.getLong("CatalogID"))) {

qb.append(" and CatalogID=?", params.getLong("CatalogID"));

}

DataTable dt = qb.fetch(pageSize, pageIndex);

for (DataRow dr : dt) {

list.add(dr.getLong("ID"));

}

return list;

}

public List<Document> parseDocument(DAOSet<ZCComment> set) {

List<Document> docs = new ArrayList<Document>();// 每个document代表一条评论记录

for (ZCComment c : set) {

Document doc = getDocument(c);

if (doc != null && doc.getFields() != null && doc.getFields().size() > 0) {

docs.add(getDocument(c));

}

}

return docs;

}

public Document getDocument(ZCComment c) {

List<Field> fields = getFields();

Document doc = new Document();

ZCCatalog catalog = CatalogUtil.getDAO(c.getCatalogID());

for (Field field : fields) {

if (StringUtil.isNotNull(field.stringValue())) {

doc.add(field);

continue;

}

if ("INDEXTYPE".equals(field.name())) {

field.setValue(ID);// 检索类型

else if ("ID".equals(field.name())) {

field.setValue(String.valueOf(c.getID()));

else if ("TITLE".equals(field.name())) {

field.setValue(c.getTitle() == null ? "" : c.getTitle());

else if ("CONTENT".equals(field.name())) {

field.setValue(c.getContent() == null ? "" : c.getContent());

else if ("_KEYWORD".equals(field.name())) {

String keyword = c.getContent() == null ? "" : c.getContent() + " ";

keyword += c.getTitle() == null ? "" : c.getTitle();

field.setValue(keyword);

else if ("SITEID".equals(field.name())) {

field.setValue(String.valueOf(c.getSiteID()));

else if ("RELACONTENTID".equals(field.name())) {

field.setValue(String.valueOf(c.getRelaID()));

else if ("CATALOGID".equals(field.name())) {

field.setValue(String.valueOf(c.getCatalogID()));

else if ("CATALOGINNERCODE".equals(field.name())) {

field.setValue(c.getCatalogInnerCode());

else if ("CATALOGTYPE".equals(field.name())) {

field.setValue(c.getCatalogType());

else if ("CATALOGNAME".equals(field.name())) {

field.setValue(catalog.getName());

else if ("INDEXENABLE".equals(field.name())) {

if (catalog != null) {

field.setValue(IndexEnable.getValue(catalog.getConfigProps()) ? YesOrNo.Yes : YesOrNo.No);

else {

field.setValue(YesOrNo.Yes);

}

else if ("VERIFYFLAG".equals(field.name())) {

field.setValue(c.getVerifyFlag());

else if ("VERIFYUSER".equals(field.name())) {

field.setValue(c.getVerifyUser());

else if ("VERIFYTIME".equals(field.name())) {

field.setValue(ObjectUtil.empty(c.getVerifyTime()) ? "" : DateUtil.toDateTimeString(c.getVerifyTime()));

else if ("ADDTIME".equals(field.name())) {

field.setValue(ObjectUtil.empty(c.getAddTime()) ? "" : DateUtil.toDateTimeString(c.getAddTime()));

else if ("MODIFYTIME".equals(field.name())) {

field.setValue(ObjectUtil.empty(c.getModifyTime()) ? "" : DateUtil.toDateTimeString(c.getModifyTime()));

}

doc.add(field);

}

return doc;

}

}

 

 

注册检索类型扩展项

  向全文检索类型扩展服务SearchService注册检索类型扩展项

1

 

创建索引

  启动应用,系统定时任务IndexTask会定时调用SingleIndexerstart()方法创建索引。

 

按条件搜索

  生成的索引通过统一查询入口SearchService获取数据。实现步骤如下:1、获取索引参数 2、获取搜索器 3、返回搜索结果。

  获取数据的示例代码如下:

public DataTable getSearchList(DataGridAction dga) {

/*

 * 准备索引参数

 */

ArrayList<SearchParam> sps = new ArrayList<SearchParam>();

//按字段条件查询

sps.add(new SearchParam("INDEXTYPE", MyTestIndexType.ID, SearchParam.SearchType.Equal, Occur.MUST));

if (ObjectUtil.notEmpty($V("SiteID"))) {// 站点ID

sps.add(new SearchParam("SITEID", $V("SiteID"), SearchParam.SearchType.Equal, Occur.MUST));

}

if (!YesOrNo.isYes($V("TitleOnly"))) {

sps.add(new SearchParam("TITLE", $V("Keyword"), SearchParam.SearchType.Fulltext));

sps.add(new SearchParam("CONTENT", $V("Keyword"), SearchParam.SearchType.Fulltext));

sps.add(new SearchParam("_KEYWORD", $V("Keyword"), SearchParam.SearchType.Fulltext, Occur.MUST));

else {

sps.add(new SearchParam("TITLE", $V("Keyword"), SearchParam.SearchType.Fulltext, Occur.MUST));

}

//左相似检索

if (ObjectUtil.notEmpty($V("CatalogInnerCode"))) {

sps.add(new SearchParam("CATALOGINNERCODE", $V("CatalogInnerCode"), SearchParam.SearchType.LeftLike, Occur.MUST));

}

//前台搜索只能搜索到开启了检索的栏目下的内容

sps.add(new SearchParam("INDEXENABLE", YesOrNo.Yes, SearchParam.SearchType.Equal, Occur.MUST));

sps.add(new SearchParam("PAGESIZE", dga.getPageSize() + "", SearchParam.SearchType.PageSize));

sps.add(new SearchParam("PAGEINDEX", dga.getPageIndex() + "", SearchParam.SearchType.PageIndex));

//前台搜索只能搜到已经通过审核的评论

sps.add(new SearchParam("VERIFYFLAG", YesOrNo.Yes, SearchParam.SearchType.Equal, Occur.MUST));

//根据时间范围查询

if (StringUtil.isNotEmpty($V("StartTime")) && StringUtil.isNotEmpty($V("EndTime"))) {

sps.add(new SearchParam("VERIFYTIME", $V("StartTime"), $V("EndTime"), SearchParam.SearchType.DateRange));

}

//多字段共同排序

if (StringUtil.isNotEmpty($V("Sort"))) {

String[] sorts = StringUtil.splitEx($V("Sort"), ",");

for (String sort : sorts) {

sps.add(new SearchParam(sort, null, SearchParam.SearchType.Sort, Occur.MUST));

}

}

/*

 * 获取搜索器进行搜索

 */

SearchResult sr = SearchService.search(sps, true);

dga.setTotal(sr.Total);

//当没有搜索到记录,不保存到热门词汇中

if(sr==null||sr.Total<1){

return sr.Data;

}

/*

 * 搜索结果

 */

DataTable dt = sr.Data;

if (dt != null && dt.getRowCount() > 0) {

// 记录关键词搜索统计

SearchWordStat.getInstance().stat(sps);

}

return dt;

  }