diff --git a/CHANGES.txt b/CHANGES.txt index e16ed29a330..c196e0beeeb 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -254,6 +254,10 @@ New Features that allows disabling of english possessive stemming (removal of trailing 's from tokens) (Robert Muir via yonik) +66. SOLR-1237: firstSearcher and newSearcher can now be identified via the CommonParams.EVENT (evt) parameter in a request. This allows a + RequestHandler or SearchComponent to know when a newSearcher or firstSearcher event happened. QuerySenderListender is the only implementation + in Solr that implements this, but outside implementations may wish to. See the AbstractSolrEventListener for a helper method. (gsingers) + Optimizations ---------------------- diff --git a/src/common/org/apache/solr/common/params/EventParams.java b/src/common/org/apache/solr/common/params/EventParams.java new file mode 100644 index 00000000000..5a5e3b2198c --- /dev/null +++ b/src/common/org/apache/solr/common/params/EventParams.java @@ -0,0 +1,13 @@ +package org.apache.solr.common.params; + + +/** + * + * + **/ +public interface EventParams { + /** Event param for things like newSearcher, firstSearcher**/ + public static final String EVENT = "event"; + public static final String NEW_SEARCHER = "newSearcher"; + public static final String FIRST_SEARCHER = "firstSearcher"; +} diff --git a/src/java/org/apache/solr/core/AbstractSolrEventListener.java b/src/java/org/apache/solr/core/AbstractSolrEventListener.java index 54b7de7e791..8f0680e8c94 100644 --- a/src/java/org/apache/solr/core/AbstractSolrEventListener.java +++ b/src/java/org/apache/solr/core/AbstractSolrEventListener.java @@ -18,6 +18,7 @@ package org.apache.solr.core; import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.params.EventParams; import org.apache.solr.search.SolrIndexSearcher; /** @@ -44,4 +45,25 @@ class AbstractSolrEventListener implements SolrEventListener { public String toString() { return getClass().getName() + args; } + + /** + * Add the {@link org.apache.solr.common.params.EventParams#EVENT} with either the {@link org.apache.solr.common.params.EventParams#NEW_SEARCHER} + * or {@link org.apache.solr.common.params.EventParams#FIRST_SEARCHER} values depending on the value of currentSearcher. + *

+ * Makes a copy of NamedList and then adds the parameters. + * + * + * @param currentSearcher If null, add FIRST_SEARCHER, otherwise NEW_SEARCHER + * @param nlst The named list to add the EVENT value to + */ + protected NamedList addEventParms(SolrIndexSearcher currentSearcher, NamedList nlst) { + NamedList result = new NamedList(); + result.addAll(nlst); + if (currentSearcher != null) { + result.add(EventParams.EVENT, EventParams.NEW_SEARCHER); + } else { + result.add(EventParams.EVENT, EventParams.FIRST_SEARCHER); + } + return result; + } } diff --git a/src/java/org/apache/solr/core/QuerySenderListener.java b/src/java/org/apache/solr/core/QuerySenderListener.java index 14de9bc6eed..b7935b023a8 100644 --- a/src/java/org/apache/solr/core/QuerySenderListener.java +++ b/src/java/org/apache/solr/core/QuerySenderListener.java @@ -42,7 +42,8 @@ class QuerySenderListener extends AbstractSolrEventListener { for (NamedList nlst : (List)args.get("queries")) { try { // bind the request to a particular searcher (the newSearcher) - LocalSolrQueryRequest req = new LocalSolrQueryRequest(core,nlst) { + NamedList params = addEventParms(currentSearcher, nlst); + LocalSolrQueryRequest req = new LocalSolrQueryRequest(core,params) { @Override public SolrIndexSearcher getSearcher() { return searcher; } @Override public void close() { } }; @@ -75,5 +76,4 @@ class QuerySenderListener extends AbstractSolrEventListener { } - } diff --git a/src/java/org/apache/solr/core/SolrEventListener.java b/src/java/org/apache/solr/core/SolrEventListener.java index eaab004d317..2f0d21e0e90 100644 --- a/src/java/org/apache/solr/core/SolrEventListener.java +++ b/src/java/org/apache/solr/core/SolrEventListener.java @@ -36,6 +36,28 @@ public interface SolrEventListener { /** The searchers passed here are only guaranteed to be valid for the duration * of this method call, so care should be taken not to spawn threads or asynchronous * tasks with references to these searchers. + *

+ * Implementations should add the {@link org.apache.solr.common.params.EventParams#EVENT} parameter and set it to a value of either: + *

+ * + * Sample: + *
+    if (currentSearcher != null) {
+      nlst.add(CommonParams.EVENT, CommonParams.NEW_SEARCHER);
+    } else {
+      nlst.add(CommonParams.EVENT, CommonParams.FIRST_SEARCHER);
+    }
+   *
+   * 
+ * + * @see org.apache.solr.core.AbstractSolrEventListener#addEventParms(org.apache.solr.search.SolrIndexSearcher, org.apache.solr.common.util.NamedList) + * + * @param newSearcher The new {@link org.apache.solr.search.SolrIndexSearcher} to use + * @param currentSearcher The existing {@link org.apache.solr.search.SolrIndexSearcher}. null if this is a firstSearcher event. + * */ public void newSearcher(SolrIndexSearcher newSearcher, SolrIndexSearcher currentSearcher); diff --git a/src/test/org/apache/solr/core/MockQuerySenderListenerReqHandler.java b/src/test/org/apache/solr/core/MockQuerySenderListenerReqHandler.java new file mode 100644 index 00000000000..a814b4953c1 --- /dev/null +++ b/src/test/org/apache/solr/core/MockQuerySenderListenerReqHandler.java @@ -0,0 +1,40 @@ +package org.apache.solr.core; + +import org.apache.solr.handler.RequestHandlerBase; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.request.SolrQueryResponse; + + +/** + * + * + **/ +public class MockQuerySenderListenerReqHandler extends RequestHandlerBase { + public SolrQueryRequest req; + public SolrQueryResponse rsp; + + public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + this.req = req; + this.rsp = rsp; + } + + public String getDescription() { + String result = null; + return result; + } + + public String getSourceId() { + String result = null; + return result; + } + + public String getSource() { + String result = null; + return result; + } + + public String getVersion() { + String result = null; + return result; + } +} diff --git a/src/test/org/apache/solr/core/TestQuerySenderListener.java b/src/test/org/apache/solr/core/TestQuerySenderListener.java index e57d0b3be7d..91e51def2cb 100644 --- a/src/test/org/apache/solr/core/TestQuerySenderListener.java +++ b/src/test/org/apache/solr/core/TestQuerySenderListener.java @@ -17,11 +17,10 @@ package org.apache.solr.core; -import org.apache.solr.handler.RequestHandlerBase; -import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.request.SolrQueryResponse; -import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.util.AbstractSolrTestCase; +import org.apache.solr.search.SolrIndexSearcher; +import org.apache.solr.common.params.EventParams; +import org.apache.lucene.store.Directory; public class TestQuerySenderListener extends AbstractSolrTestCase { @@ -35,5 +34,28 @@ public class TestQuerySenderListener extends AbstractSolrTestCase { assertEquals( 1, core.firstSearcherListeners.size() ); assertEquals( 1, core.newSearcherListeners.size() ); } + + public void testSearcherEvents() throws Exception { + SolrCore core = h.getCore(); + SolrEventListener newSearcherListener = core.newSearcherListeners.get(0); + assertTrue("Not an instance of QuerySenderListener", newSearcherListener instanceof QuerySenderListener); + QuerySenderListener qsl = (QuerySenderListener) newSearcherListener; + + SolrIndexSearcher currentSearcher = core.getSearcher().get(); + qsl.newSearcher(currentSearcher, null);//test new Searcher + MockQuerySenderListenerReqHandler mock = (MockQuerySenderListenerReqHandler) core.getRequestHandler("mock"); + assertNotNull("Mock is null", mock); + String evt = mock.req.getParams().get(EventParams.EVENT); + assertNotNull("Event is null", evt); + assertTrue(evt + " is not equal to " + EventParams.FIRST_SEARCHER, evt.equals(EventParams.FIRST_SEARCHER) == true); + Directory dir = currentSearcher.getReader().directory(); + SolrIndexSearcher newSearcher = new SolrIndexSearcher(core, core.getSchema(), "testQuerySenderListener", dir, true, false); + + qsl.newSearcher(newSearcher, currentSearcher); + evt = mock.req.getParams().get(EventParams.EVENT); + assertNotNull("Event is null", evt); + assertTrue(evt + " is not equal to " + EventParams.NEW_SEARCHER, evt.equals(EventParams.NEW_SEARCHER) == true); + } + } diff --git a/src/test/test-files/solr/conf/solrconfig-querysender.xml b/src/test/test-files/solr/conf/solrconfig-querysender.xml index 7de8035624c..449d5dbedf3 100644 --- a/src/test/test-files/solr/conf/solrconfig-querysender.xml +++ b/src/test/test-files/solr/conf/solrconfig-querysender.xml @@ -34,8 +34,8 @@ local query request for each NamedList in sequence. --> - solr 0 10 - rocks 0 10 + solr 0 10 mock + rocks 0 10 mock @@ -44,10 +44,15 @@ requests or to gain prewarming data from. --> - fast_warm 0 10 + fast_warm 0 10 + mock + - + + + +