package com.jspxcms.core.fulltext;
import static org.apache.lucene.document.Field.Index.ANALYZED;
import static org.apache.lucene.document.Field.Index.NOT_ANALYZED;
import static org.apache.lucene.document.Field.Store.NO;
import static org.apache.lucene.document.Field.Store.YES;
import static org.apache.lucene.search.BooleanClause.Occur.MUST;
import static org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
import static org.apache.lucene.util.Version.LUCENE_36;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
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.Term;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.NumericUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.util.NumberUtils;
import com.jspxcms.common.fulltext.LuceneException;
import com.jspxcms.core.domain.Attribute;
import com.jspxcms.core.domain.Info;
import com.jspxcms.core.domain.Node;
import com.mysema.query.BooleanBuilder;
import com.mysema.query.types.PathMetadataFactory;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.path.ArrayPath;
import com.mysema.query.types.path.DateTimePath;
import com.mysema.query.types.path.EntityPathBase;
import com.mysema.query.types.path.NumberPath;
import com.mysema.query.types.path.StringPath;
/**
* 信息实体的全文检索转换类
*
* @author liufang
*
*/
public class FInfo extends EntityPathBase<Document> {
private static final long serialVersionUID = 1L;
public FInfo(String var) {
super(Document.class, PathMetadataFactory.forVariable(var));
}
public static final FInfo info = new FInfo("info");
public static final String ID = "id";
public static final String SITE_ID = "siteId";
public static final String NODE_ID = "nodeId";
public static final String ATTR_ID = "attrId";
public static final String PUBLISH_DATE = "publishDate";
public static final String STATUS = "status";
public static final String TITLE = "title";
public static final String KEYWORDS = "keywords";
public static final String DESCRIPTION = "description";
public static final String TEXT = "text";
public final NumberPath<Integer> id = createNumber(ID, Integer.class);
public final NumberPath<Integer> siteId = createNumber(SITE_ID,
Integer.class);
public final ArrayPath<Integer> nodeId = createArray(NODE_ID,
Integer[].class);
public final ArrayPath<Integer> attrId = createArray(ATTR_ID,
Integer[].class);
public final DateTimePath<Date> publishDate = createDateTime(PUBLISH_DATE,
Date.class);
public final StringPath status = createString(STATUS);
public final StringPath title = createString(TITLE);
public final StringPath keywords = createString(KEYWORDS);
public final StringPath description = createString(DESCRIPTION);
public final StringPath text = createString(TEXT);
public static List<Integer> idsFromDoc(List<Document> docList) {
if (!docList.isEmpty()) {
List<Integer> ids = new ArrayList<Integer>(docList.size());
for (Document doc : docList) {
ids.add(NumberUtils.parseNumber(doc.get(ID), Integer.class));
}
return ids;
} else {
return Collections.emptyList();
}
}
public static List<Integer> idsFromString(List<String> idList) {
if (!idList.isEmpty()) {
List<Integer> ids = new ArrayList<Integer>(idList.size());
for (String id : idList) {
ids.add(NumberUtils.parseNumber(id, Integer.class));
}
return ids;
} else {
return Collections.emptyList();
}
}
public static Term id(Integer id) {
return new Term(FInfo.ID, NumericUtils.intToPrefixCoded(id));
}
public static Document doc(Info info) {
Document doc = new Document();
NumericField id = new NumericField(ID, YES, true);
doc.add(id.setIntValue(info.getId()));
NumericField siteId = new NumericField(SITE_ID);
doc.add(siteId.setIntValue(info.getSite().getId()));
NumericField nodeId = new NumericField(NODE_ID);
Node node = info.getNode();
while (node != null) {
doc.add(nodeId.setIntValue(node.getId()));
node = node.getParent();
}
List<Attribute> attrs = info.getAttrs();
if (!CollectionUtils.isEmpty(attrs)) {
for (Attribute attr : attrs) {
doc.add(new NumericField(ATTR_ID).setIntValue(attr.getId()));
}
}
NumericField publishDate = new NumericField(PUBLISH_DATE);
doc.add(publishDate.setLongValue(info.getPublishDate().getTime()));
doc.add(new Field(STATUS, info.getStatus(), NO, NOT_ANALYZED));
StringBuilder titleBuff = new StringBuilder();
String title = info.getTitle();
if (StringUtils.isNotBlank(title)) {
titleBuff.append(title);
}
title = info.getSubtitle();
if (StringUtils.isNotBlank(title)) {
titleBuff.append(title);
}
title = info.getFullTitle();
if (StringUtils.isNotBlank(title)) {
titleBuff.append(title);
}
title = titleBuff.toString();
if (StringUtils.isNotBlank(title)) {
doc.add(new Field(TITLE, title, NO, ANALYZED));
}
String keywords = info.getTagKeywords();
if (StringUtils.isNotBlank(keywords)) {
doc.add(new Field(KEYWORDS, keywords, NO, ANALYZED));
}
String description = info.getMetaDescription();
if (StringUtils.isNotBlank(description)) {
doc.add(new Field(DESCRIPTION, description, NO, ANALYZED));
}
String text = info.getPlainText();
if (StringUtils.isNotBlank(text)) {
doc.add(new Field(TEXT, text, NO, ANALYZED));
}
return doc;
}
public static Query query(Analyzer analyzer, Integer[] siteIds,
Integer[] nodeIds, Integer[] attrIds, Date startDate, Date endDate,
String[] status, Integer[] excludeId, String q, String title,
String keywords, String description, String text) {
try {
BooleanQuery query = new BooleanQuery();
if (ArrayUtils.isNotEmpty(siteIds)) {
BooleanQuery qy = new BooleanQuery();
for (Integer id : siteIds) {
String s = NumericUtils.intToPrefixCoded(id);
qy.add(new TermQuery(new Term(SITE_ID, s)), SHOULD);
}
query.add(qy, MUST);
}
if (ArrayUtils.isNotEmpty(nodeIds)) {
BooleanQuery qy = new BooleanQuery();
for (Integer id : nodeIds) {
String s = NumericUtils.intToPrefixCoded(id);
qy.add(new TermQuery(new Term(NODE_ID, s)), SHOULD);
}
query.add(qy, MUST);
}
if (ArrayUtils.isNotEmpty(attrIds)) {
BooleanQuery qy = new BooleanQuery();
for (Integer id : attrIds) {
String s = NumericUtils.intToPrefixCoded(id);
qy.add(new TermQuery(new Term(ATTR_ID, s)), SHOULD);
}
query.add(qy, MUST);
}
if (startDate != null || endDate != null) {
Long min = startDate != null ? startDate.getTime() : null;
Long max = endDate != null ? endDate.getTime() : null;
NumericRangeQuery.newLongRange(PUBLISH_DATE, min, max, true,
true);
}
if (ArrayUtils.isNotEmpty(status)) {
BooleanQuery qy = new BooleanQuery();
for (String s : status) {
qy.add(new TermQuery(new Term(STATUS, s)), SHOULD);
}
query.add(qy, MUST);
}
if (ArrayUtils.isNotEmpty(excludeId)) {
for (Integer id : excludeId) {
query.add(new TermQuery(id(id)), MUST_NOT);
}
}
if (StringUtils.isNotBlank(q)) {
Query qy = MultiFieldQueryParser.parse(LUCENE_36, q,
new String[] { TITLE, KEYWORDS, DESCRIPTION, TEXT },
new Occur[] { SHOULD, SHOULD, SHOULD, SHOULD },
analyzer);
query.add(qy, MUST);
}
if (StringUtils.isNotBlank(title)) {
QueryParser p = new QueryParser(LUCENE_36, TITLE, analyzer);
query.add(p.parse(title), MUST);
}
if (StringUtils.isNotBlank(keywords)) {
QueryParser p = new QueryParser(LUCENE_36, KEYWORDS, analyzer);
query.add(p.parse(title), MUST);
}
if (StringUtils.isNotBlank(description)) {
QueryParser p = new QueryParser(LUCENE_36, DESCRIPTION,
analyzer);
query.add(p.parse(title), MUST);
}
if (StringUtils.isNotBlank(text)) {
QueryParser p = new QueryParser(LUCENE_36, TEXT, analyzer);
query.add(p.parse(title), MUST);
}
return query;
} catch (Exception e) {
throw new LuceneException("Error during create query.", e);
}
}
public static Predicate query(Integer[] siteIds, Integer[] nodeIds,
Integer[] attrIds, Date startDate, Date endDate, String[] status,
Integer[] excludeId, String q, String title, String keywords,
String description, String text) {
FInfo info = FInfo.info;
BooleanBuilder exp = new BooleanBuilder();
if (ArrayUtils.isNotEmpty(siteIds)) {
exp = exp.and(info.siteId.in(siteIds));
}
if (ArrayUtils.isNotEmpty(nodeIds)) {
exp = exp.and(info.nodeId.in(nodeIds));
}
if (ArrayUtils.isNotEmpty(attrIds)) {
exp = exp.and(info.attrId.in(attrIds));
}
if (startDate != null) {
exp = exp.and(info.publishDate.goe(startDate));
}
if (endDate != null) {
exp = exp.and(info.publishDate.loe(endDate));
}
if (ArrayUtils.isNotEmpty(status)) {
exp = exp.and(info.status.in(status));
}
if (ArrayUtils.isNotEmpty(excludeId)) {
exp = exp.and(info.id.notIn(excludeId));
}
if (StringUtils.isNotBlank(q)) {
exp = exp
.and(info.title.contains(q).or(info.keywords.contains(q))
.or(info.description.contains(q))
.or(info.text.contains(q)));
}
if (StringUtils.isNotBlank(title)) {
exp = exp.and(info.title.contains(title));
}
if (StringUtils.isNotBlank(keywords)) {
exp = exp.and(info.keywords.contains(keywords));
}
if (StringUtils.isNotBlank(description)) {
exp = exp.and(info.description.contains(description));
}
if (StringUtils.isNotBlank(text)) {
exp = exp.and(info.text.contains(text));
}
return exp;
}
}