001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.solr.tst;
017:
018: import org.apache.lucene.search.*;
019: import org.apache.lucene.document.Document;
020: import org.apache.lucene.document.Field;
021: import org.apache.lucene.index.IndexReader;
022:
023: import java.util.*;
024: import java.util.regex.Pattern;
025: import java.util.logging.Logger;
026: import java.util.logging.Level;
027: import java.net.URL;
028:
029: import org.apache.solr.util.StrUtils;
030: import org.apache.solr.util.NamedList;
031: import org.apache.solr.util.OpenBitSet;
032: import org.apache.solr.search.*;
033: import org.apache.solr.core.SolrCore;
034: import org.apache.solr.core.SolrException;
035: import org.apache.solr.request.SolrRequestHandler;
036: import org.apache.solr.request.SolrQueryRequest;
037: import org.apache.solr.request.SolrQueryResponse;
038:
039: /**
040: * @author yonik
041: * @version $Id: TestRequestHandler.java 542679 2007-05-29 22:28:21Z ryan $
042: */
043:
044: public class TestRequestHandler implements SolrRequestHandler {
045: private static Logger log = Logger
046: .getLogger(SolrIndexSearcher.class.getName());
047:
048: public void init(NamedList args) {
049: SolrCore.log.log(Level.INFO,
050: "Unused request handler arguments:" + args);
051: }
052:
053: // use test instead of assert since asserts may be turned off
054: public void test(boolean condition) {
055: try {
056: if (!condition) {
057: throw new RuntimeException(
058: "test requestHandler: assertion failed!");
059: }
060: } catch (RuntimeException e) {
061: SolrException.log(log, e);
062: throw (e);
063: }
064: }
065:
066: private long numRequests;
067: private long numErrors;
068:
069: private final Pattern splitList = Pattern.compile(",| ");
070:
071: public void handleRequest(SolrQueryRequest req,
072: SolrQueryResponse rsp) {
073: numRequests++;
074:
075: // TODO: test if lucene will accept an escaped ';', otherwise
076: // we need to un-escape them before we pass to QueryParser
077: try {
078: String sreq = req.getQueryString();
079: if (sreq == null)
080: throw new SolrException(
081: SolrException.ErrorCode.BAD_REQUEST,
082: "Missing queryString");
083: List<String> commands = StrUtils.splitSmart(sreq, ';');
084:
085: String qs = commands.size() >= 1 ? commands.get(0) : "";
086: Query query = QueryParsing.parseQuery(qs, req.getSchema());
087:
088: // find fieldnames to return (fieldlist)
089: String fl = req.getParam("fl");
090: int flags = 0;
091: if (fl != null) {
092: // TODO - this could become more efficient if widely used.
093: // TODO - should field order be maintained?
094: String[] flst = splitList.split(fl, 0);
095: if (flst.length > 0
096: && !(flst.length == 1 && flst[0].length() == 0)) {
097: Set<String> set = new HashSet<String>();
098: for (String fname : flst) {
099: if ("score".equals(fname))
100: flags |= SolrIndexSearcher.GET_SCORES;
101: set.add(fname);
102: }
103: rsp.setReturnFields(set);
104: }
105: }
106:
107: // If the first non-query, non-filter command is a simple sort on an indexed field, then
108: // we can use the Lucene sort ability.
109: Sort sort = null;
110: if (commands.size() >= 2) {
111: QueryParsing.SortSpec sortSpec = QueryParsing
112: .parseSort(commands.get(1), req.getSchema());
113: if (sortSpec != null) {
114: sort = sortSpec.getSort();
115: // ignore the count for now... it's currently only controlled by start & limit on req
116: // count = sortSpec.getCount();
117: }
118: }
119:
120: SolrIndexSearcher searcher = req.getSearcher();
121:
122: /***
123: Object o = searcher.cacheLookup("dfllNode", query);
124: if (o == null) {
125: searcher.cacheInsert("dfllNode",query,"Hello Bob");
126: } else {
127: System.out.println("User Cache Hit On " + o);
128: }
129: ***/
130:
131: int start = req.getStart();
132: int limit = req.getLimit();
133:
134: Query filterQuery = null;
135: DocSet filter = null;
136: Filter lfilter = null;
137:
138: DocList results = req.getSearcher().getDocList(query, null,
139: sort, req.getStart(), req.getLimit(), flags);
140: rsp.add(null, results);
141:
142: if (qs.startsWith("values")) {
143: rsp.add("testname1", "testval1");
144:
145: rsp.add("testarr1", new String[] { "my val 1",
146: "my val 2" });
147:
148: NamedList nl = new NamedList();
149: nl.add("myInt", 333);
150: nl.add("myNullVal", null);
151: nl.add("myFloat", 1.414213562f);
152: nl.add("myDouble", 1e100d);
153: nl.add("myBool", false);
154: nl.add("myLong", 999999999999L);
155:
156: Document doc = new Document();
157: doc.add(new Field("id", "55", Field.Store.YES,
158: Field.Index.UN_TOKENIZED));
159: nl.add("myDoc", doc);
160:
161: nl.add("myResult", results);
162: nl.add("myStr", "&wow! test escaping: a&b<c&");
163: nl.add(null, "this value had a null name...");
164: nl.add("myIntArray", new Integer[] { 100, 5, -10, 42 });
165: nl.add("epoch", new Date(0));
166: nl
167: .add("currDate", new Date(System
168: .currentTimeMillis()));
169: rsp.add("myNamedList", nl);
170: } else if (qs.startsWith("fields")) {
171: NamedList nl = new NamedList();
172: Collection flst;
173: flst = searcher.getReader().getFieldNames(
174: IndexReader.FieldOption.INDEXED);
175: nl.add("indexed", flst);
176: flst = searcher.getReader().getFieldNames(
177: IndexReader.FieldOption.UNINDEXED);
178: nl.add("unindexed", flst);
179: rsp.add("fields", nl);
180: }
181:
182: test(results.size() <= limit);
183: test(results.size() <= results.matches());
184: // System.out.println("limit="+limit+" results.size()="+results.size()+" matches="+results.matches());
185: test((start == 0 && limit >= results.matches()) ? results
186: .size() == results.matches() : true);
187:
188: //
189: // test against hits
190: //
191: Hits hits = searcher.search(query, lfilter, sort);
192: test(hits.length() == results.matches());
193:
194: DocList rrr2 = results.subset(start, limit);
195: test(rrr2 == results);
196:
197: DocIterator iter = results.iterator();
198:
199: /***
200: for (int i=0; i<hits.length(); i++) {
201: System.out.println("doc="+hits.id(i) + " score="+hits.score(i));
202: }
203: ***/
204:
205: for (int i = 0; i < results.size(); i++) {
206: test(iter.nextDoc() == hits.id(i + results.offset()));
207:
208: // Document doesn't implement equals()
209: // test( searcher.document(i).equals(hits.doc(i)));
210: }
211:
212: DocList results2 = req.getSearcher().getDocList(query,
213: query, sort, start, limit);
214: test(results2.size() == results.size()
215: && results2.matches() == results.matches());
216: DocList results3 = req.getSearcher().getDocList(query,
217: query, null, start, limit);
218: test(results3.size() == results.size()
219: && results3.matches() == results.matches());
220:
221: //
222: // getting both the list and set
223: //
224: DocListAndSet both = searcher.getDocListAndSet(query,
225: filter, sort, start, limit);
226: test(both.docList.equals(results));
227: test(both.docList.matches() == both.docSet.size());
228: test((start == 0 && both.docSet.size() <= limit) ? both.docSet
229: .equals(both.docList)
230: : true);
231:
232: // use the result set as a filter itself...
233: DocListAndSet both2 = searcher.getDocListAndSet(query,
234: both.docSet, sort, start, limit);
235: test(both2.docList.equals(both.docList));
236: test(both2.docSet.equals(both.docSet));
237:
238: // use the query as a filter itself...
239: DocListAndSet both3 = searcher.getDocListAndSet(query,
240: query, sort, start, limit);
241: test(both3.docList.equals(both.docList));
242: test(both3.docSet.equals(both.docSet));
243:
244: OpenBitSet bits = both.docSet.getBits();
245: OpenBitSet neg = ((OpenBitSet) bits.clone());
246: neg.flip(0, bits.capacity());
247:
248: // use the negative as a filter (should result in 0 matches)
249: // todo - fix if filter is not null
250: both2 = searcher.getDocListAndSet(query,
251: new BitDocSet(neg), sort, start, limit);
252: test(both2.docList.size() == 0);
253: test(both2.docList.matches() == 0);
254: test(both2.docSet.size() == 0);
255:
256: DocSet allResults = searcher.getDocSet(query, filter);
257: test(allResults.equals(both.docSet));
258:
259: if (filter != null) {
260: DocSet res = searcher.getDocSet(query);
261: test(res.size() >= results.size());
262: test(res.intersection(filter).equals(both.docSet));
263:
264: test(res.intersectionSize(filter) == both.docSet.size());
265: if (filterQuery != null) {
266: test(searcher.numDocs(filterQuery, res) == both.docSet
267: .size());
268: }
269: }
270:
271: } catch (Exception e) {
272: rsp.setException(e);
273: numErrors++;
274: return;
275: }
276: }
277:
278: //////////////////////// SolrInfoMBeans methods //////////////////////
279:
280: public String getName() {
281: return TestRequestHandler.class.getName();
282: }
283:
284: public String getVersion() {
285: return SolrCore.version;
286: }
287:
288: public String getDescription() {
289: return "A test handler that runs some sanity checks on results";
290: }
291:
292: public Category getCategory() {
293: return Category.QUERYHANDLER;
294: }
295:
296: public String getSourceId() {
297: return "$Id: TestRequestHandler.java 542679 2007-05-29 22:28:21Z ryan $";
298: }
299:
300: public String getSource() {
301: return "$URL: https://svn.apache.org/repos/asf/lucene/solr/branches/branch-1.2/src/java/org/apache/solr/tst/TestRequestHandler.java $";
302: }
303:
304: public URL[] getDocs() {
305: return null;
306: }
307:
308: public NamedList getStatistics() {
309: NamedList lst = new NamedList();
310: lst.add("requests", numRequests);
311: lst.add("errors", numErrors);
312: return lst;
313: }
314:
315: }
|