/* * Created on Jul 19, 2006 */ package org.openedit.data.lucene; import java.util.Date; import java.util.List; import org.apache.lucene.document.DateTools; import org.apache.lucene.document.DateTools.Resolution; import org.apache.lucene.queryparser.classic.QueryParser; import org.apache.lucene.search.NumericRangeQuery; import org.apache.lucene.search.Query; import org.openedit.data.PropertyDetail; import org.openedit.data.Searcher; import com.openedit.hittracker.SearchQuery; import com.openedit.hittracker.Term; public class LuceneSearchQuery extends SearchQuery { protected List <PropertyDetail> fieldFacetList; public LuceneSearchQuery() { // TODO Auto-generated constructor stub } protected transient NumberUtils fieldNumberUtils; public NumberUtils getNumberUtils() { if (fieldNumberUtils == null) { fieldNumberUtils = new NumberUtils(); } return fieldNumberUtils; } public void setNumberUtils(NumberUtils inNumberUtils) { fieldNumberUtils = inNumberUtils; } public Term addAfter(PropertyDetail inFieldId,final Date inDate) { Term term = new Term() { public String toQuery() { String date = DateTools.dateToString(inDate, Resolution.SECOND); String fin = getDetail().getId() + ":[" + date + " TO 99999999999999]"; return fin; } }; term.setDetail(inFieldId); term.setValue(getDateFormat().format(inDate)); term.setOperation("afterdate"); addTermByDataType(term); return term; } protected void addTermByDataType(Term inTerm) { PropertyDetail searchdetail = inTerm.getDetail(); if( searchdetail.isDataType("searchjoin" ) ) { //split it String id = searchdetail.getId(); String localfield = id.substring(0, id.indexOf('.')); String remotefield = id.substring(id.indexOf('.') + 1); String remotejoincolumn = searchdetail.get("foreignkeyid"); //This is the parent. That is not the same thing as the list Searcher remotesearcher = getSearcherManager().getSearcher(searchdetail.getCatalogId(), localfield); SearchQuery q = remotesearcher.createSearchQuery(); PropertyDetail detail = remotesearcher.getDetail(remotefield); //why is this null? // if( detail == null) // { // detail = remotesearcher.getDetail(remotejoincolumn); //This makes sense when using users table // } inTerm.setDetail(detail); q.addTerm(inTerm); addRemoteJoin(q, remotejoincolumn, false, localfield, localfield); //We dont actually add a term Term stub = new Term() { public String toQuery() { return null; } }; stub.setDetail(searchdetail); stub.setValues(inTerm.getValues()); stub.setValue(inTerm.getValue()); super.addTermByDataType(stub); } else { super.addTermByDataType(inTerm); } } public Term addBetween(PropertyDetail inFieldId, final Date inAfter, final Date inBefore) { Term term = new Term() { public String toQuery() { String lowDate = DateTools.dateToString(inAfter, Resolution.SECOND); String highDate = DateTools.dateToString(inBefore, Resolution.SECOND); String fin = getDetail().getId() + ":[" + lowDate + " TO " + highDate + "]"; return fin; } }; String lowDate = getDateFormat().format(inAfter); String highDate = getDateFormat().format(inBefore); term.setValue(lowDate + " - " + highDate); term.setDetail(inFieldId); term.addParameter("afterDate", lowDate); term.addParameter("beforeDate", highDate); term.setOperation("betweendates"); addTermByDataType(term); return term; } public Term addBefore(PropertyDetail inField,final Date inDate) { Term term = new Term() { public String toQuery() { String date = DateTools.dateToString(inDate, Resolution.SECOND); String fin = getDetail().getId() + ":[00000000000000 TO " +date + "]"; return fin; } }; term.setOperation("beforedate"); term.setDetail(inField); term.setValue(getDateFormat().format(inDate)); addTermByDataType(term); return term; } public Term addOrsGroup(PropertyDetail inField, String inValue) { Term term = new Term() { public String toQuery() { StringBuffer orString = new StringBuffer(); String[] orwords = getValue().split("\\s+"); if (orwords.length > 0) { orString.append("("); for (int i = 0; i < orwords.length - 1; i++) { if(orwords[i].length() > 0) { orString.append(orwords[i]); orString.append(" OR "); } } orString.append(orwords[orwords.length - 1]); orString.append(")"); } return getDetail().getId() + ":" + orString.toString(); } }; term.setDetail(inField); term.setId(inField.getId()); term.setValue(inValue); term.setOperation("orgroup"); addTermByDataType(term); return term; } //Allows any kind of syntax such as + - " " does no escape public Term addMatches(PropertyDetail inField, String inValue) { Term term = new Term() { public String toQuery() { String inVal = getValue(); if( inVal == null ) { return null; } if( inVal.startsWith("'") && inVal.endsWith("'")) { inVal = inVal.replace('\'', '\"'); } // if( !inVal.startsWith("+") && !inVal.startsWith("-") ) // { // inVal = inVal.replace("*", "REPLACESTAR"); // inVal = QueryParser.escape(inVal); // inVal = inVal.replace("REPLACESTAR","*"); // } if (getDetail().getId() != null) { return getDetail().getId() + ":(" + inVal + ")"; } else { return inVal; } } }; term.setOperation("matches"); term.setDetail(inField); term.setValue(inValue); addTermByDataType(term); return term; } public Term addContains(PropertyDetail inField, String inValue) { Term term = new Term() { public String toQuery() { String inVal = getValue(); if( inVal == null ) { return null; } //I assume you cant mix exact searching with * * if( inVal.startsWith("'") && inVal.endsWith("'")) { inVal = inVal.substring(1); inVal = inVal.substring(0,inVal.length()-2); } if( inVal.startsWith("\"") && inVal.endsWith("\"")) { inVal = inVal.substring(1); inVal = inVal.substring(0,inVal.length()-2); } inVal = QueryParser.escape(inVal); if (getDetail().getId() != null) { return getDetail().getId() + ":(*" + inVal + "*)"; } else { return inVal; } } }; term.setOperation("matches"); //tricky term.setDetail(inField); term.setValue(inValue); addTermByDataType(term); return term; } public Term addStartsWith(PropertyDetail inField, String inVal) { Term term = new Term() { public String toQuery() { StringBuffer q = new StringBuffer(); q.append(getDetail().getId()); q.append(":("); if (getValue().equals("*") ) { q.append(getValue()); } else if ( getValue().startsWith("\"")) { q.append(getValue()); } else { //Deal with multiple words City Group String value = getValue(); value = QueryParser.escape(value); String[] spaces = value.split("\\s+"); for (int i = 0; i < spaces.length; i++) { String chunk = spaces[i]; q.append(chunk); if (chunk.indexOf('*') == -1) { q.append('*'); } if (i + 1 < spaces.length) { q.append(' '); } } } q.append(")"); return q.toString(); } }; term.setOperation("startswith"); term.setDetail(inField); term.setValue(inVal); addTermByDataType(term); return term; } public Term addNots(PropertyDetail inField, String inNots) { Term term = new Term() { public String toQuery() { StringBuffer orString = new StringBuffer(); String[] notwords = getValue().split("\\s"); if (notwords.length > 0) { orString.append("( NOT "); for (int i = 0; i < notwords.length - 1; i++) { if(notwords[i].length() > 0) { //orString.append(orwords[i]); //orString.append(" OR "); orString.append(notwords[i]); orString.append(" NOT "); } } orString.append(notwords[notwords.length - 1]); orString.append(")"); } return getDetail().getId() + ":" + orString.toString(); } }; term.setOperation("notgroup"); term.setDetail(inField); term.setValue(inNots); term.setId(inField.getId()); addTermByDataType(term); return term; } public Term addExact(PropertyDetail inField, String inValue) { Term term = new Term() { public String toQuery() { String val = getValue(); if( val == null) { return null; } if(val.startsWith("\"")) { val = val.substring(1); } if(val.endsWith("\"")) { val = val.substring(0,val.length()-2); } val = QueryParser.escape(val); return getDetail().getId() + ":\"" + val + "\""; } }; term.setOperation("exact"); term.setDetail(inField); term.setValue(inValue); addTermByDataType(term); return term; } public void addExact(String inValue) { Term term = new Term() { public String toQuery() { return "\"" + getValue() + "\""; } }; term.setOperation("exact"); term.setValue(inValue); addTermByDataType(term); } public Term addNot(PropertyDetail inField, String inVal) { Term term = new Term() { public String toQuery() { return "-" + getDetail().getId() + ":" + getValue(); } }; term.setDetail(inField); term.setValue(inVal); term.setOperation("not"); addTermByDataType(term); return term; } /* is this used anyplace? public void addCategoryFilter(List inRemaining, String inFriendly) { final List categories = inRemaining; Term term = new Term() { public String toQuery() { return "-" + getId() + ":" + getValue() + ""; } public Element toXml() { Element term = DocumentHelper.createElement("term"); term.addAttribute("id", getId()); term.addAttribute("val", getValue()); term.addAttribute("op", "categoryfilter"); for (Iterator iterator = categories.iterator(); iterator.hasNext();) { String category = (String) iterator.next(); Element cat = term.addElement("category"); cat.addAttribute("categoryid", category); } return term; } }; term.setId("category"); StringBuffer all = new StringBuffer(); all.append("("); for (Iterator iter = inRemaining.iterator(); iter.hasNext();) { String cat = (String) iter.next(); all.append(cat); all.append(" "); } all.append(")"); term.setValue(all.toString()); addTerm(term); } */ public Term addLessThan(PropertyDetail inFieldId, long val) { return addBetween(inFieldId, 0L, val); } public Term addGreaterThan(PropertyDetail inFieldId,final long high) { return addBetween(inFieldId, high, Long.MAX_VALUE); } public Term addExact(PropertyDetail inField, long inParseInt) { Term term = new Term() { public String toQuery() { //TermQuery numberQuery = new TermQuery(new Term("myLongId", NumericUtils.longToPrefixCoded(12345L))) Long targetval = Long.parseLong(getValue()); Query q = NumericRangeQuery.newLongRange(getDetail().getId(),targetval, targetval, true, true); return q.toString(); // String val = getNumberUtils().long2sortableStr(getValue()); // String fin = getDetail().getId() + ":\"" + val + "\""; // return fin; } }; term.setOperation("exact"); term.setDetail(inField); term.setValue(String.valueOf(inParseInt)); addTermByDataType(term); return term; } public Term addExact(PropertyDetail inField, double inParseInt) { Term term = new Term() { public String toQuery() { //TermQuery numberQuery = new TermQuery(new Term("myLongId", NumericUtils.longToPrefixCoded(12345L))) Double targetval = Double.parseDouble(getValue()); Query q = NumericRangeQuery.newDoubleRange(getDetail().getId(),targetval, targetval, true, true); return q.toString(); // String val = getNumberUtils().long2sortableStr(getValue()); // String fin = getDetail().getId() + ":\"" + val + "\""; // return fin; } }; term.setOperation("exact"); term.setDetail(inField); term.setValue(String.valueOf(inParseInt)); addTermByDataType(term); return term; } public Term addBetween(PropertyDetail inField, long lowval, long highval) { // lowval = pad(lowval); // highval = pad(highval); Term term = new Term() { public String toQuery() { Long low = Long.parseLong(getParameter("lowval")); Long high = Long.parseLong(getParameter("highval")); Query q = NumericRangeQuery.newLongRange(getDetail().getId(),low, high, true, true); String fin = q.toString(); String lowvals = getParameter("lowval"); String highvals = getParameter("highval"); fin = getDetail().getId() + ":[" + lowvals + " TO " + highvals+ "]"; return fin; } }; term.setDetail(inField); term.setOperation("betweennumbers"); term.addParameter("lowval", String.valueOf( lowval ) ); term.addParameter("highval", String.valueOf(highval)); term.setValue(lowval + " to " + highval); addTermByDataType(term); return term; } public Term addBetween(PropertyDetail inField, double lowval, double highval) { // lowval = pad(lowval); // highval = pad(highval); //TODO: Fix Doubles - same as Long. Term term = new Term() { public String toQuery() { Double low = Double.parseDouble(getParameter("lowval")); Double high = Double.parseDouble(getParameter("highval")); Query q = NumericRangeQuery.newDoubleRange(getDetail().getId(),low, high, true, true); String fin = q.toString(); String lowvals = getParameter("lowval"); String highvals = getParameter("highval"); fin = getDetail().getId() + ":[" + lowvals + " TO " + highvals+ "]"; return fin; } }; term.setDetail(inField); term.setOperation("betweennumbers"); term.addParameter("lowval", String.valueOf( lowval ) ); term.addParameter("highval", String.valueOf(highval)); term.setValue(lowval + " to " + highval); addTermByDataType(term); return term; } public Term addFreeFormQuery(PropertyDetail inField, String inValue) { if( inValue != null && !inValue.contains("NOT ") && !inValue.contains("AND ") && !inValue.contains("OR ") && !inValue.contains(":") && !inValue.contains("*") && !inValue.contains("!") && !inValue.contains("-") && !inValue.contains("+")) { return addContains(inField, inValue); } Term term = new Term() { public String toQuery() { String inVal = getValue(); return inVal; } }; term.setOperation("freeform"); term.setDetail(inField); term.setValue(inValue); addTermByDataType(term); return term; } public String toQuery() { StringBuffer done = new StringBuffer(); String op = null; if (isAndTogether()) { op = "+"; } else { op = " OR "; } if( fieldTerms != null && getTerms().size() > 0) { for (int i = 0; i < fieldTerms.size(); i++) { Term field = (Term) fieldTerms.get(i); String q = field.toQuery(); if( q == null ) { continue; } if (i > 0 && !q.startsWith("+") && !q.startsWith("-")) { done.append(op); } done.append(q); if (i + 1 < fieldTerms.size()) { done.append(" "); } } // if (!isAndTogether()) // { // done.append(")"); // } } if( fieldChildren != null && fieldChildren.size() > 0) { if( done.length() > 0 ) { done.append(" "); } for (int j = 0; j < getChildren().size(); j++) { SearchQuery child = (SearchQuery) getChildren().get(j); String query = child.toQuery(); boolean enclose = true; if (query.startsWith("+") || query.startsWith("-")) enclose = false; //&& !query.startsWith("+") && !query.startsWith("-") if (j > 0 ) { done.append(" "); if( isAndTogether()) { if (enclose) { done.append("+("); } } else { done.append("OR "); if (enclose) { done.append("("); } } } else if (enclose) { done.append("("); } done.append(query); if (enclose) { done.append(")"); } } } return done.toString(); } }