package org.sothis.dal.solr; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.TimeZone; import org.apache.commons.lang3.time.FastDateFormat; import org.apache.lucene.index.Term; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.BooleanClause; 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.search.TermRangeQuery; import org.apache.lucene.util.BytesRef; import org.sothis.core.util.StringUtils; public class LuceneQueryBuilder { private BooleanQuery booleanQuery = new BooleanQuery(); public final static FastDateFormat DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", TimeZone.getTimeZone("UTC")); /** * 约定:以$$开头的字符串不需要特殊字符转义 */ public final static String NO_ESCAPSE = "$$"; public LuceneQueryBuilder range(String field, Object min, Object max, boolean minInclusive, boolean maxInclusive, BooleanClause.Occur occur) { if (min != null || max != null) { Object obj = null == min ? max : min; Query query = null; if (Integer.class.isInstance(obj)) { query = NumericRangeQuery.newIntRange(field, (Integer) min, (Integer) max, minInclusive, maxInclusive); } else if (Long.class.isInstance(obj)) { query = NumericRangeQuery.newLongRange(field, (Long) min, (Long) max, minInclusive, maxInclusive); } else if (Double.class.isInstance(obj)) { query = NumericRangeQuery.newDoubleRange(field, (Double) min, (Double) max, minInclusive, maxInclusive); } else if (Float.class.isInstance(obj)) { query = NumericRangeQuery.newFloatRange(field, (Float) min, (Float) max, minInclusive, maxInclusive); } else if (Date.class.isInstance(obj)) { query = new TermRangeQuery(field, null == min ? new BytesRef() : new BytesRef(DATE_FORMAT.format((Date) min) .getBytes()), null == max ? new BytesRef() : new BytesRef(DATE_FORMAT.format((Date) max).getBytes()), minInclusive, maxInclusive); } else { query = new TermRangeQuery(field, null == min ? new BytesRef() : new BytesRef(min.toString().getBytes()), null == max ? new BytesRef() : new BytesRef(max.toString().getBytes()), minInclusive, maxInclusive); } booleanQuery.add(query, occur); } return this; } public LuceneQueryBuilder range(String field, Object min, Object max, boolean minInclusive, boolean maxInclusive) { return range(field, min, max, minInclusive, maxInclusive, BooleanClause.Occur.MUST); } public LuceneQueryBuilder range(String field, Object min, Object max) { return range(field, min, max, true, true, BooleanClause.Occur.MUST); } public LuceneQueryBuilder range(String field, Object min, Object max, BooleanClause.Occur occur) { return range(field, min, max, true, true, occur); } public LuceneQueryBuilder gt(String field, Object value) { return range(field, value, null, false, true, BooleanClause.Occur.MUST); } public LuceneQueryBuilder gt(String field, Object value, BooleanClause.Occur occur) { return range(field, value, null, false, true, occur); } public LuceneQueryBuilder gte(String field, Object value) { return range(field, value, null, true, true, BooleanClause.Occur.MUST); } public LuceneQueryBuilder gte(String field, Object value, BooleanClause.Occur occur) { return range(field, value, null, true, true, occur); } public LuceneQueryBuilder lt(String field, Object value) { return range(field, null, value, true, false, BooleanClause.Occur.MUST); } public LuceneQueryBuilder lt(String field, Object value, BooleanClause.Occur occur) { return range(field, null, value, true, false, occur); } public LuceneQueryBuilder lte(String field, Object value) { return range(field, null, value, true, true, BooleanClause.Occur.MUST); } public LuceneQueryBuilder lte(String field, Object value, BooleanClause.Occur occur) { return range(field, null, value, true, true, occur); } public LuceneQueryBuilder eq(String field, Object value, BooleanClause.Occur occur) { if (null != value) { Query query = new TermQuery(new Term(field, value.toString())); booleanQuery.add(query, occur); } return this; } public LuceneQueryBuilder eq(String field, Object value) { return eq(field, getRealValue(value), BooleanClause.Occur.MUST); } public LuceneQueryBuilder eq(String field, Object value, boolean escapse) { return eq(field, escapse ? QueryParser.escape(value.toString()) : value.toString(), BooleanClause.Occur.MUST); } public LuceneQueryBuilder ne(String field, Object value) { return eq(field, getRealValue(value), BooleanClause.Occur.MUST_NOT); } public LuceneQueryBuilder ne(String field, Object value, BooleanClause.Occur occur) { return eq(field, getRealValue(value), occur); } public LuceneQueryBuilder in(String field, List<Object> value, boolean escapse, BooleanClause.Occur occur) { if (null == value || value.isEmpty()) { throw new IllegalArgumentException("in query with null or empty list!!"); } BooleanQuery bQuery = new BooleanQuery(); for (Object v : value) { Query query = new TermQuery(new Term(field, escapse ? QueryParser.escape(v.toString()) : v.toString())); bQuery.add(query, BooleanClause.Occur.SHOULD); } booleanQuery.add(bQuery, occur); return this; } public LuceneQueryBuilder in(String field, List<Object> value) { return in(field, getRealValue(value), false, BooleanClause.Occur.MUST); } public LuceneQueryBuilder in(String field, List<Object> value, BooleanClause.Occur occur) { return in(field, getRealValue(value), false, occur); } public LuceneQueryBuilder in(String field, List<Object> value, boolean escapse) { return in(field, value, escapse, BooleanClause.Occur.MUST); } public Query toQuery() { return this.booleanQuery; } /** * 获取真实value<br/> * 如果是非string的value,返回转义后的原值<br/> * 如果是string型,如果以$$开头,则截取$$后面的字符且不需要转义 * * @param value * @return */ private Object getRealValue(Object value) { if (value instanceof String) { if (NO_ESCAPSE.equals(value)) { return value; } else if (StringUtils.startsWith((String) value, NO_ESCAPSE)) { return StringUtils.substring((String) value, NO_ESCAPSE.length()); } } return QueryParser.escape(value.toString()); } private List<Object> getRealValue(List<Object> value) { if (null == value || value.isEmpty()) { return value; } List<Object> ret = new ArrayList<Object>(value.size()); for (Object v : value) { ret.add(getRealValue(v)); } return ret; } }