001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.search.lucene2.query; 020 021import java.io.IOException; 022import java.io.StringReader; 023import java.util.Map; 024import java.util.Vector; 025import java.util.WeakHashMap; 026 027import lucee.commons.lang.ParserString; 028 029import org.apache.lucene.analysis.Analyzer; 030import org.apache.lucene.analysis.TokenStream; 031import org.apache.lucene.index.Term; 032import org.apache.lucene.search.BooleanQuery; 033import org.apache.lucene.search.FuzzyQuery; 034import org.apache.lucene.search.PhraseQuery; 035import org.apache.lucene.search.PrefixQuery; 036import org.apache.lucene.search.Query; 037import org.apache.lucene.search.TermQuery; 038import org.apache.lucene.search.WildcardQuery; 039 040/** 041 * @deprecated no longer in use 042 * The simple query is the default query type and is appropriate for the vast majority of searches. 043 * When entering text on a search form, you perform a simple query by entering a word or comma-delimited strings, 044 * with optional wildcard characters. 045 * Verity treats each comma as a logical OR. If you omit the commas, Verity treats the expression as a phrase. 046 */ 047public final class Simple { 048 private String OR="or"; 049 private String AND="and"; 050 private String NOT="not"; 051 private char QUOTER='"'; 052 private String FIELD="contents"; 053 054 private static final short TYPE_TERMAL=0; 055 private static final short TYPE_WILDCARD=1; 056 private static final short TYPE_PREFIX=2; 057 private static final short TYPE_FUZZY=3; 058 private static final short TYPE_PHRASE=4; 059 060 private Analyzer analyzer; 061 062 private Map results=new WeakHashMap(); 063 064 /** 065 * constructor of the class 066 * @param analyzer 067 */ 068 public Simple(Analyzer analyzer) { 069 this.analyzer=analyzer; 070 071 } 072 /** 073 * parse given string query 074 * @param criteria 075 * @return matching Query 076 */ 077 public Query parse(String criteria) { 078 Query qry=(Query) results.get(criteria); 079 if(qry!=null) return qry; 080 081 // remove operators at start 082 if(criteria.length()>0) { 083 char first=criteria.charAt(0); 084 // start with operator 085 while(first=='*' || first=='~' || first=='?') { 086 criteria=criteria.substring(1); 087 if(criteria.length()==0) break; 088 first=criteria.charAt(0); 089 } 090 } 091 092 // make never foud query if quey is empty 093 if(criteria.length()==0) { 094 BooleanQuery bool = new BooleanQuery(); 095 bool.add(new TermQuery(new Term(FIELD, "dshnuiaslfspfhsadhfisd")), OccurUtil.toOccur(false, true)); 096 results.put(criteria,bool); 097 return bool; 098 } 099 100 ParserString ps=new ParserString(criteria); 101 qry= orOp(ps); 102 results.put(criteria,qry); 103 return qry; 104 } 105 106 107 108 private Query orOp(ParserString ps) { 109 Query query=andOp(ps); 110 ps.removeSpace(); 111 112 // OR 113 while(ps.isValidIndex() && ps.forwardIfCurrent(OR) || ps.forwardIfCurrent(',')) { 114 ps.removeSpace(); 115 BooleanQuery bool = new BooleanQuery(); 116 117 bool.add(query, OccurUtil.toOccur(false, false)); 118 //bool.add(query, false, false); 119 bool.add(andOp(ps), OccurUtil.toOccur(false, false)); 120 query = bool; 121 } 122 return query; 123 } 124 125 private Query andOp(ParserString ps) { 126 Query query = notOp(ps); 127 ps.removeSpace(); 128 129 // AND 130 while(ps.isValidIndex() && ps.forwardIfCurrent(AND)) { 131 ps.removeSpace(); 132 BooleanQuery bool = new BooleanQuery(); 133 bool.add(query, OccurUtil.toOccur(true, false)); 134 bool.add(notOp(ps), OccurUtil.toOccur(true, false)); 135 query = bool; 136 } 137 return query; 138 } 139 private Query notOp(ParserString ps) { 140 // NOT 141 if(ps.isValidIndex() && ps.forwardIfCurrent(NOT)) { 142 ps.removeSpace(); 143 BooleanQuery bool = new BooleanQuery(); 144 bool.add(clip(ps), OccurUtil.toOccur(false, true)); 145 return bool; 146 } 147 return clip(ps); 148 } 149 150 private Query clip(ParserString ps) { 151 // () 152 if(ps.isValidIndex() && ps.forwardIfCurrent('(')) { 153 Query query=orOp(ps); 154 ps.removeSpace(); 155 ps.forwardIfCurrent(')'); 156 ps.removeSpace(); 157 return query; 158 } 159 return literal(ps); 160 } 161 162 private Query literal(ParserString ps) { 163 _Term term=term(ps); 164 ps.removeSpace(); 165 while(ps.isValidIndex() && !ps.isCurrent(',') && !ps.isCurrent(OR) && !ps.isCurrent(AND) && !ps.isCurrent(')')) { 166 term.append(term(ps)); 167 ps.removeSpace(); 168 } 169 return term.toQuery(); 170 } 171 172 private _Term term(ParserString ps) { 173 short type=TYPE_TERMAL; 174 ps.removeSpace(); 175 StringBuffer sb=new StringBuffer(); 176 boolean inside=false; 177 char c=0; 178 while(ps.isValidIndex() && ((c=ps.getCurrentLower())!=' ' && c!=',' && c!=')' || inside)) { 179 ps.next(); 180 if(c==QUOTER) { 181 inside=!inside; 182 type=TYPE_PHRASE; 183 continue; 184 } 185 sb.append(c); 186 if(!inside) { 187 if(type==TYPE_PREFIX)type=TYPE_WILDCARD; 188 if(type==TYPE_TERMAL && c=='*')type=TYPE_PREFIX; 189 if(c=='?')type=TYPE_WILDCARD; 190 if(type==TYPE_TERMAL && c=='~') { 191 type=TYPE_FUZZY; 192 break; 193 } 194 } 195 } 196 return new _Term(type,sb.toString()); 197 198 } 199 200 class _Term { 201 private short type; 202 private String content; 203 204 private _Term(short type, String content) { 205 this.type = type; 206 this.content=content; 207 } 208 209 private void append(_Term term) { 210 content+=' '+term.content; 211 type=TYPE_PHRASE; 212 } 213 214 private Query toQuery() { 215 if(type==TYPE_FUZZY) return toFuzzyQuery(); 216 else if(type==TYPE_WILDCARD) return new WildcardQuery(toTerm()); 217 else if(type==TYPE_PREFIX)return toPrefixQuery(); 218 else if(type==TYPE_PHRASE) return toPhraseQuery(); 219 return new TermQuery(toTerm()); 220 } 221 222 private FuzzyQuery toFuzzyQuery() { 223 String c=toContent(); 224 return new FuzzyQuery(new Term(FIELD,c.substring(0,c.length()-1))); 225 } 226 227 private PrefixQuery toPrefixQuery() { 228 String c=toContent(); 229 return new PrefixQuery(new Term(FIELD,c.substring(0,c.length()-1))); 230 } 231 232 private PhraseQuery toPhraseQuery() { 233 234 235 TokenStream source = analyzer.tokenStream(FIELD,new StringReader(content)); 236 Vector v = new Vector(); 237 org.apache.lucene.analysis.Token t; 238 239 while (true) { 240 try { 241 t = source.next(); 242 } 243 catch (IOException e) { 244 t = null; 245 } 246 if (t == null) 247 break; 248 v.addElement(t.termText()); 249 } 250 try { 251 source.close(); 252 } 253 catch (IOException e) { 254 // ignore 255 } 256 257 PhraseQuery q = new PhraseQuery(); 258 q.setSlop(0); 259 260 for (int i=0; i<v.size(); i++) { 261 q.add(new Term(FIELD, (String) v.elementAt(i))); 262 } 263 return q; 264 265 } 266 267 private String toContent() { 268 return content; 269 } 270 private Term toTerm() { 271 return new Term(FIELD, toContent()); 272 } 273 @Override 274 public String toString() { 275 return toContent(); 276 } 277 } 278}