Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

support multiple q parameters in one call.

  • Loading branch information...
commit 766d874162311deec731aeedcdd502236e3c53df 1 parent b248025
Robert Newson authored
View
2  README.md
@@ -340,7 +340,7 @@ The following parameters can be passed for more sophisticated searches;
<dt>force_json<dt><dd>Usually couchdb-lucene determines the Content-Type of its response based on the presence of the Accept header. If Accept contains "application/json", you get "application/json" in the response, otherwise you get "text/plain;charset=utf8". Some tools, like JSONView for FireFox, do not send the Accept header but do render "application/json" responses if received. Setting force_json=true forces all response to "application/json" regardless of the Accept header.</dd>
<dt>include_docs</dt><dd>whether to include the source docs</dd>
<dt>limit</dt><dd>the maximum number of results to return</dd>
-<dt>q</dt><dd>the query to run (e.g, subject:hello). If not specified, the default field is searched.</dd>
+<dt>q</dt><dd>the query to run (e.g, subject:hello). If not specified, the default field is searched. Multiple q parameters are permitted, the resulting JSON will be an array of responses.</dd>
<dt>skip</dt><dd>the number of results to skip</dd>
<dt>sort</dt><dd>the comma-separated fields to sort on. Prefix with / for ascending order and \ for descending order (ascending is the default if not specified). Type-specific sorting is also available by appending a : and the sort type as normal (e.g, 'sort=amount:float'). Supported types are 'float', 'double', 'int', 'long' and 'date'.</dd>
<dt>stale=ok</dt><dd>If you set the <i>stale</i> option to <i>ok</i>, couchdb-lucene may not perform any refreshing on the index. Searches may be faster as Lucene caches important data (especially for sorting). A query without stale=ok will use the latest data committed to the index.</dd>
View
4 src/main/java/com/github/rnewson/couchdb/lucene/CustomQueryParser.java
@@ -29,7 +29,7 @@ public CustomQueryParser(final Version matchVersion, final String f, final Analy
super(matchVersion, f, a);
}
- public Sort toSort(final String sort) {
+ public static Sort toSort(final String sort) {
if (sort == null) {
return null;
} else {
@@ -69,7 +69,7 @@ public Sort toSort(final String sort) {
}
}
- public String toString(final SortField[] sortFields) {
+ public static String toString(final SortField[] sortFields) {
final JSONArray result = new JSONArray();
for (final SortField field : sortFields) {
final JSONObject col = new JSONObject();
View
24 src/main/java/com/github/rnewson/couchdb/lucene/QueryPlan.java
@@ -17,7 +17,11 @@
* @author robertnewson
*
*/
-public class QueryPlan {
+public final class QueryPlan {
+
+ private QueryPlan() {
+
+ }
/**
* Produces a string representation of the query classes used for a query.
@@ -25,20 +29,20 @@
* @param query
* @return
*/
- public String toPlan(final Query query) {
+ public static String toPlan(final Query query) {
final StringBuilder builder = new StringBuilder(300);
toPlan(builder, query);
return builder.toString();
}
- private void planBooleanQuery(final StringBuilder builder, final BooleanQuery query) {
+ private static void planBooleanQuery(final StringBuilder builder, final BooleanQuery query) {
for (final BooleanClause clause : query.getClauses()) {
builder.append(clause.getOccur());
toPlan(builder, clause.getQuery());
}
}
- private void planFuzzyQuery(final StringBuilder builder, final FuzzyQuery query) {
+ private static void planFuzzyQuery(final StringBuilder builder, final FuzzyQuery query) {
builder.append(query.getTerm());
builder.append(",prefixLength=");
builder.append(query.getPrefixLength());
@@ -46,7 +50,7 @@ private void planFuzzyQuery(final StringBuilder builder, final FuzzyQuery query)
builder.append(query.getMinSimilarity());
}
- private void planNumericRangeQuery(final StringBuilder builder, final NumericRangeQuery<?> query) {
+ private static void planNumericRangeQuery(final StringBuilder builder, final NumericRangeQuery<?> query) {
builder.append(query.getMin());
builder.append(" TO ");
builder.append(query.getMax());
@@ -54,25 +58,25 @@ private void planNumericRangeQuery(final StringBuilder builder, final NumericRan
builder.append(query.getMin().getClass().getSimpleName());
}
- private void planPrefixQuery(final StringBuilder builder, final PrefixQuery query) {
+ private static void planPrefixQuery(final StringBuilder builder, final PrefixQuery query) {
builder.append(query.getPrefix());
}
- private void planTermQuery(final StringBuilder builder, final TermQuery query) {
+ private static void planTermQuery(final StringBuilder builder, final TermQuery query) {
builder.append(query.getTerm());
}
- private void planTermRangeQuery(final StringBuilder builder, final TermRangeQuery query) {
+ private static void planTermRangeQuery(final StringBuilder builder, final TermRangeQuery query) {
builder.append(query.getLowerTerm());
builder.append(" TO ");
builder.append(query.getUpperTerm());
}
- private void planWildcardQuery(final StringBuilder builder, final WildcardQuery query) {
+ private static void planWildcardQuery(final StringBuilder builder, final WildcardQuery query) {
builder.append(query.getTerm());
}
- private void toPlan(final StringBuilder builder, final Query query) {
+ private static void toPlan(final StringBuilder builder, final Query query) {
builder.append(query.getClass().getSimpleName());
builder.append("(");
if (query instanceof TermQuery) {
View
96 src/main/java/com/github/rnewson/couchdb/lucene/SearchServlet.java
@@ -16,6 +16,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
@@ -23,6 +24,7 @@
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
+import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.FieldDoc;
@@ -68,7 +70,7 @@ protected void doGet(final HttpServletRequest req, final HttpServletResponse res
}
final boolean debug = getBooleanParameter(req, "debug");
- final boolean rewrite_query = getBooleanParameter(req, "rewrite_query");
+ final boolean rewrite_query = getBooleanParameter(req, "rewrite");
final boolean staleOk = Utils.getStaleOk(req);
final IndexPath path = IndexPath.parse(req);
@@ -93,24 +95,55 @@ public void callback(final IndexSearcher searcher, final String version) throws
final Analyzer analyzer = Analyzers.getAnalyzer(getParameter(req, "analyzer", "standard"));
final CustomQueryParser parser = new CustomQueryParser(Version.LUCENE_CURRENT, Constants.DEFAULT_FIELD, analyzer);
- final Query q;
+ final String[] queries = req.getParameterValues("q");
+ final JSONArray arr = new JSONArray();
+
+ for (final String query : queries) {
+ try {
+ arr.add(performQuery(debug, rewrite_query, searcher, version, parser.parse(query)));
+ } catch (final ParseException e) {
+ ServletUtils.sendJSONError(req, resp, 400, "Bad query syntax");
+ return;
+ }
+ }
+
+ Utils.setResponseContentTypeAndEncoding(req, resp);
+
+ // Cache-related headers.
+ resp.setHeader("ETag", version);
+ resp.setHeader("Cache-Control", "must-revalidate");
+
+ final JSON json = arr.size() > 1 ? arr : arr.getJSONObject(0);
+
+ // Format response body.
+ final String callback = req.getParameter("callback");
+ final String body;
+ if (callback != null) {
+ body = String.format("%s(%s)", callback, json);
+ } else {
+ body = json.toString(debug ? 2 : 0);
+ }
+
+ final Writer writer = resp.getWriter();
try {
- q = parser.parse(req.getParameter("q"));
- } catch (final ParseException e) {
- ServletUtils.sendJSONError(req, resp, 400, "Bad query syntax");
- return;
+ writer.write(body);
+ } finally {
+ writer.close();
}
+ }
- final JSONObject json = new JSONObject();
- json.put("q", q.toString());
+ private JSONObject performQuery(final boolean debug, final boolean rewrite_query, final IndexSearcher searcher,
+ final String version, final Query q) throws IOException, CorruptIndexException {
+ final JSONObject result = new JSONObject();
+ result.put("q", q.toString());
if (debug) {
- json.put("plan", new QueryPlan().toPlan(q));
+ result.put("plan", QueryPlan.toPlan(q));
}
- json.put("etag", version);
+ result.put("etag", version);
if (rewrite_query) {
final Query rewritten_q = q.rewrite(searcher.getIndexReader());
- json.put("rewritten_q", rewritten_q.toString());
+ result.put("rewritten_q", rewritten_q.toString());
final JSONObject freqs = new JSONObject();
@@ -120,7 +153,7 @@ public void callback(final IndexSearcher searcher, final String version) throws
final int freq = searcher.docFreq((Term) term);
freqs.put(term, freq);
}
- json.put("freqs", freqs);
+ result.put("freqs", freqs);
} else {
// Perform the search.
final TopDocs td;
@@ -128,7 +161,7 @@ public void callback(final IndexSearcher searcher, final String version) throws
final boolean include_docs = getBooleanParameter(req, "include_docs");
final int limit = getIntParameter(req, "limit", 25);
- final Sort sort = parser.toSort(req.getParameter("sort"));
+ final Sort sort = CustomQueryParser.toSort(req.getParameter("sort"));
final int skip = getIntParameter(req, "skip", 0);
if (sort == null) {
@@ -213,39 +246,18 @@ public void callback(final IndexSearcher searcher, final String version) throws
}
stopWatch.lap("fetch");
- json.put("skip", skip);
- json.put("limit", limit);
- json.put("total_rows", td.totalHits);
- json.put("search_duration", stopWatch.getElapsed("search"));
- json.put("fetch_duration", stopWatch.getElapsed("fetch"));
+ result.put("skip", skip);
+ result.put("limit", limit);
+ result.put("total_rows", td.totalHits);
+ result.put("search_duration", stopWatch.getElapsed("search"));
+ result.put("fetch_duration", stopWatch.getElapsed("fetch"));
// Include sort info (if requested).
if (td instanceof TopFieldDocs) {
- json.put("sort_order", parser.toString(((TopFieldDocs) td).fields));
+ result.put("sort_order", CustomQueryParser.toString(((TopFieldDocs) td).fields));
}
- json.put("rows", rows);
- }
-
- Utils.setResponseContentTypeAndEncoding(req, resp);
-
- // Cache-related headers.
- resp.setHeader("ETag", version);
- resp.setHeader("Cache-Control", "must-revalidate");
-
- // Format response body.
- final String callback = req.getParameter("callback");
- final String body;
- if (callback != null) {
- body = String.format("%s(%s)", callback, json);
- } else {
- body = json.toString(debug ? 2 : 0);
- }
-
- final Writer writer = resp.getWriter();
- try {
- writer.write(body);
- } finally {
- writer.close();
+ result.put("rows", rows);
}
+ return result;
}
public void onMissing() throws IOException {
Please sign in to comment.
Something went wrong with that request. Please try again.