You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by cp...@apache.org on 2016/02/12 21:16:33 UTC
lucene-solr git commit: SOLR-5730: Make Lucene's SortingMergePolicy
and EarlyTerminatingSortingCollector configurable in Solr.
Repository: lucene-solr
Updated Branches:
refs/heads/master 77558a649 -> 677779086
SOLR-5730: Make Lucene's SortingMergePolicy and EarlyTerminatingSortingCollector configurable in Solr.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/67777908
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/67777908
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/67777908
Branch: refs/heads/master
Commit: 677779086c87db33406f3344736187fa10a30901
Parents: 77558a6
Author: Christine Poerschke <cp...@apache.org>
Authored: Fri Feb 12 20:16:02 2016 +0000
Committer: Christine Poerschke <cp...@apache.org>
Committed: Fri Feb 12 20:16:02 2016 +0000
----------------------------------------------------------------------
solr/CHANGES.txt | 7 +-
.../solr/handler/component/QueryComponent.java | 41 ++-
.../solr/handler/component/ResponseBuilder.java | 4 +
.../solr/index/SortingMergePolicyFactory.java | 51 ++++
.../apache/solr/response/SolrQueryResponse.java | 1 +
.../org/apache/solr/search/QueryCommand.java | 12 +
.../org/apache/solr/search/QueryResult.java | 9 +
.../apache/solr/search/SolrIndexSearcher.java | 20 ++
.../solr/update/DefaultSolrCoreState.java | 18 ++
.../org/apache/solr/update/SolrCoreState.java | 8 +
.../solrconfig-sortingmergepolicyfactory.xml | 50 ++++
.../solr/cloud/TestMiniSolrCloudCluster.java | 60 +++++
.../cloud/TestSegmentTerminateEarlyState.java | 255 +++++++++++++++++++
.../solr/response/TestSolrQueryResponse.java | 6 +
.../apache/solr/update/SolrIndexConfigTest.java | 27 ++
.../apache/solr/common/params/CommonParams.java | 6 +
16 files changed, 571 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 20e10ac..d7e8544 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -249,7 +249,12 @@ Other Changes
* SOLR-8529: Improve JdbcTest to not use plain assert statements (Kevin Risden, Joel Bernstein)
======================= 5.6.0 =======================
-(No Changes)
+
+New Features
+----------------------
+
+* SOLR-5730: Make Lucene's SortingMergePolicy and EarlyTerminatingSortingCollector configurable in Solr.
+ (Christine Poerschke, hossmann, Tomás Fernández Löbbe, Shai Erera)
======================= 5.5.0 =======================
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
index c855936..75238ab 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
@@ -373,11 +373,17 @@ public class QueryComponent extends SearchComponent
QueryResult result = new QueryResult();
+ cmd.setSegmentTerminateEarly(params.getBool(CommonParams.SEGMENT_TERMINATE_EARLY, CommonParams.SEGMENT_TERMINATE_EARLY_DEFAULT));
+ if (cmd.getSegmentTerminateEarly()) {
+ result.setSegmentTerminatedEarly(Boolean.FALSE);
+ }
+
//
// grouping / field collapsing
//
GroupingSpecification groupingSpec = rb.getGroupingSpec();
if (groupingSpec != null) {
+ cmd.setSegmentTerminateEarly(false); // not supported, silently ignore any segmentTerminateEarly flag
try {
boolean needScores = (cmd.getFlags() & SolrIndexSearcher.GET_SCORES) != 0;
if (params.getBool(GroupParams.GROUP_DISTRIBUTED_FIRST, false)) {
@@ -983,8 +989,10 @@ public class QueryComponent extends SearchComponent
long numFound = 0;
Float maxScore=null;
boolean partialResults = false;
+ Boolean segmentTerminatedEarly = null;
for (ShardResponse srsp : sreq.responses) {
SolrDocumentList docs = null;
+ NamedList<?> responseHeader = null;
if(shardInfo!=null) {
SimpleOrderedMap<Object> nl = new SimpleOrderedMap<>();
@@ -1003,6 +1011,11 @@ public class QueryComponent extends SearchComponent
}
}
else {
+ responseHeader = (NamedList<?>)srsp.getSolrResponse().getResponse().get("responseHeader");
+ final Object rhste = (responseHeader == null ? null : responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY));
+ if (rhste != null) {
+ nl.add(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY, rhste);
+ }
docs = (SolrDocumentList)srsp.getSolrResponse().getResponse().get("response");
nl.add("numFound", docs.getNumFound());
nl.add("maxScore", docs.getMaxScore());
@@ -1024,9 +1037,22 @@ public class QueryComponent extends SearchComponent
docs = (SolrDocumentList)srsp.getSolrResponse().getResponse().get("response");
}
- NamedList<?> responseHeader = (NamedList<?>)srsp.getSolrResponse().getResponse().get("responseHeader");
- if (responseHeader != null && Boolean.TRUE.equals(responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY))) {
- partialResults = true;
+ if (responseHeader == null) { // could have been initialized in the shards info block above
+ responseHeader = (NamedList<?>)srsp.getSolrResponse().getResponse().get("responseHeader");
+ }
+
+ if (responseHeader != null) {
+ if (Boolean.TRUE.equals(responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY))) {
+ partialResults = true;
+ }
+ if (!Boolean.TRUE.equals(segmentTerminatedEarly)) {
+ final Object ste = responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY);
+ if (Boolean.TRUE.equals(ste)) {
+ segmentTerminatedEarly = Boolean.TRUE;
+ } else if (Boolean.FALSE.equals(ste)) {
+ segmentTerminatedEarly = Boolean.FALSE;
+ }
+ }
}
// calculate global maxScore and numDocsFound
@@ -1118,6 +1144,15 @@ public class QueryComponent extends SearchComponent
rb.rsp.getResponseHeader().add(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY, Boolean.TRUE);
}
}
+ if (segmentTerminatedEarly != null) {
+ final Object existingSegmentTerminatedEarly = rb.rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY);
+ if (existingSegmentTerminatedEarly == null) {
+ rb.rsp.getResponseHeader().add(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY, segmentTerminatedEarly);
+ } else if (!Boolean.TRUE.equals(existingSegmentTerminatedEarly) && Boolean.TRUE.equals(segmentTerminatedEarly)) {
+ rb.rsp.getResponseHeader().remove(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY);
+ rb.rsp.getResponseHeader().add(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY, segmentTerminatedEarly);
+ }
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java b/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
index 8f05e26..5dd4b5c 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/ResponseBuilder.java
@@ -453,6 +453,10 @@ public class ResponseBuilder
if (result.isPartialResults()) {
rsp.getResponseHeader().add(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY, Boolean.TRUE);
}
+ final Boolean segmentTerminatedEarly = result.getSegmentTerminatedEarly();
+ if (segmentTerminatedEarly != null) {
+ rsp.getResponseHeader().add(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY, segmentTerminatedEarly);
+ }
if (null != cursorMark) {
assert null != result.getNextCursorMark() : "using cursor but no next cursor set";
this.setNextCursorMark(result.getNextCursorMark());
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/index/SortingMergePolicyFactory.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/index/SortingMergePolicyFactory.java b/solr/core/src/java/org/apache/solr/index/SortingMergePolicyFactory.java
new file mode 100644
index 0000000..4234cb4
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/index/SortingMergePolicyFactory.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.index;
+
+import org.apache.lucene.index.MergePolicy;
+import org.apache.lucene.index.SortingMergePolicy;
+import org.apache.lucene.search.Sort;
+
+import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.search.SortSpecParsing;
+
+/**
+ * A {@link MergePolicyFactory} for {@link SortingMergePolicy} objects.
+ */
+public class SortingMergePolicyFactory extends WrapperMergePolicyFactory {
+
+ static final String SORT = "sort"; // not private so that test(s) can use it
+
+ protected final Sort mergeSort;
+
+ public SortingMergePolicyFactory(SolrResourceLoader resourceLoader, MergePolicyFactoryArgs args, IndexSchema schema) {
+ super(resourceLoader, args, schema);
+ final String sortArg = (String) args.remove(SORT);
+ if (sortArg == null) {
+ throw new IllegalArgumentException(SortingMergePolicyFactory.class.getSimpleName()+" requires a '"+SORT+ "' argument.");
+ }
+ this.mergeSort = SortSpecParsing.parseSortSpec(sortArg, schema).getSort();
+ }
+
+ @Override
+ protected MergePolicy getMergePolicyInstance(MergePolicy wrappedMP) {
+ final MergePolicy mp = new SortingMergePolicy(wrappedMP, mergeSort);
+ return mp;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java b/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java
index 277848b..f1ccd08 100644
--- a/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java
+++ b/solr/core/src/java/org/apache/solr/response/SolrQueryResponse.java
@@ -67,6 +67,7 @@ import org.apache.solr.search.SolrReturnFields;
public class SolrQueryResponse {
public static final String NAME = "response";
public static final String RESPONSE_HEADER_PARTIAL_RESULTS_KEY = "partialResults";
+ public static final String RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY = "segmentTerminatedEarly";
private static final String RESPONSE_HEADER_KEY = "responseHeader";
private static final String RESPONSE_KEY = "response";
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/search/QueryCommand.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/QueryCommand.java b/solr/core/src/java/org/apache/solr/search/QueryCommand.java
index 129a5c2..553e022 100755
--- a/solr/core/src/java/org/apache/solr/search/QueryCommand.java
+++ b/solr/core/src/java/org/apache/solr/search/QueryCommand.java
@@ -207,4 +207,16 @@ public class QueryCommand {
}
}
+ public boolean getSegmentTerminateEarly() {
+ return (flags & SolrIndexSearcher.SEGMENT_TERMINATE_EARLY) != 0;
+ }
+
+ public QueryCommand setSegmentTerminateEarly(boolean segmentSegmentTerminateEarly) {
+ if (segmentSegmentTerminateEarly) {
+ return setFlags(SolrIndexSearcher.SEGMENT_TERMINATE_EARLY);
+ } else {
+ return clearFlags(SolrIndexSearcher.SEGMENT_TERMINATE_EARLY);
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/search/QueryResult.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/QueryResult.java b/solr/core/src/java/org/apache/solr/search/QueryResult.java
index c1d6528..419a8f4 100755
--- a/solr/core/src/java/org/apache/solr/search/QueryResult.java
+++ b/solr/core/src/java/org/apache/solr/search/QueryResult.java
@@ -22,6 +22,7 @@ package org.apache.solr.search;
public class QueryResult {
private boolean partialResults;
+ private Boolean segmentTerminatedEarly;
private DocListAndSet docListAndSet;
private CursorMark nextCursorMark;
@@ -57,6 +58,14 @@ public class QueryResult {
this.partialResults = partialResults;
}
+ public Boolean getSegmentTerminatedEarly() {
+ return segmentTerminatedEarly;
+ }
+
+ public void setSegmentTerminatedEarly(Boolean segmentTerminatedEarly) {
+ this.segmentTerminatedEarly = segmentTerminatedEarly;
+ }
+
public void setDocListAndSet(DocListAndSet listSet) {
docListAndSet = listSet;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
index 66c4795..8057a97 100644
--- a/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
+++ b/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
@@ -70,6 +70,7 @@ import org.apache.lucene.search.Collector;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.DocIdSet;
import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.EarlyTerminatingSortingCollector;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.FieldDoc;
import org.apache.lucene.search.IndexSearcher;
@@ -219,6 +220,20 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
private void buildAndRunCollectorChain(QueryResult qr, Query query, Collector collector, QueryCommand cmd,
DelegatingCollector postFilter) throws IOException {
+ EarlyTerminatingSortingCollector earlyTerminatingSortingCollector = null;
+ if (cmd.getSegmentTerminateEarly()) {
+ final Sort cmdSort = cmd.getSort();
+ final int cmdLen = cmd.getLen();
+ final Sort mergeSort = core.getSolrCoreState().getMergePolicySort();
+
+ if (cmdSort == null || cmdLen <= 0 || mergeSort == null ||
+ !EarlyTerminatingSortingCollector.canEarlyTerminate(cmdSort, mergeSort)) {
+ log.warn("unsupported combination: segmentTerminateEarly=true cmdSort={} cmdLen={} mergeSort={}", cmdSort, cmdLen, mergeSort);
+ } else {
+ collector = earlyTerminatingSortingCollector = new EarlyTerminatingSortingCollector(collector, cmdSort, cmd.getLen(), mergeSort);
+ }
+ }
+
final boolean terminateEarly = cmd.getTerminateEarly();
if (terminateEarly) {
collector = new EarlyTerminatingCollector(collector, cmd.getLen());
@@ -244,6 +259,10 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
((DelegatingCollector) collector).finish();
}
throw etce;
+ } finally {
+ if (earlyTerminatingSortingCollector != null) {
+ qr.setSegmentTerminatedEarly(earlyTerminatingSortingCollector.terminatedEarly());
+ }
}
if (collector instanceof DelegatingCollector) {
((DelegatingCollector) collector).finish();
@@ -1465,6 +1484,7 @@ public class SolrIndexSearcher extends IndexSearcher implements Closeable, SolrI
public static final int GET_DOCSET = 0x40000000;
static final int NO_CHECK_FILTERCACHE = 0x20000000;
static final int NO_SET_QCACHE = 0x10000000;
+ static final int SEGMENT_TERMINATE_EARLY = 0x08;
public static final int TERMINATE_EARLY = 0x04;
public static final int GET_DOCLIST = 0x02; // get the documents actually returned in a response
public static final int GET_SCORES = 0x01;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java b/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java
index 8e58c6c..8eab83f 100644
--- a/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java
+++ b/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java
@@ -28,6 +28,9 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.MergePolicy;
+import org.apache.lucene.index.SortingMergePolicy;
+import org.apache.lucene.search.Sort;
import org.apache.solr.cloud.ActionThrottle;
import org.apache.solr.cloud.RecoveryStrategy;
import org.apache.solr.common.SolrException;
@@ -239,6 +242,21 @@ public final class DefaultSolrCoreState extends SolrCoreState implements Recover
core.getSolrConfig().indexConfig, core.getDeletionPolicy(), core.getCodec());
}
+ public Sort getMergePolicySort() throws IOException {
+ lock(iwLock.readLock());
+ try {
+ if (indexWriter != null) {
+ final MergePolicy mergePolicy = indexWriter.getConfig().getMergePolicy();
+ if (mergePolicy instanceof SortingMergePolicy) {
+ return ((SortingMergePolicy)mergePolicy).getSort();
+ }
+ }
+ } finally {
+ iwLock.readLock().unlock();
+ }
+ return null;
+ }
+
@Override
public DirectoryFactory getDirectoryFactory() {
return directoryFactory;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/java/org/apache/solr/update/SolrCoreState.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/SolrCoreState.java b/solr/core/src/java/org/apache/solr/update/SolrCoreState.java
index efcf7b3..42727b4 100644
--- a/solr/core/src/java/org/apache/solr/update/SolrCoreState.java
+++ b/solr/core/src/java/org/apache/solr/update/SolrCoreState.java
@@ -21,6 +21,7 @@ import java.lang.invoke.MethodHandles;
import java.util.concurrent.locks.Lock;
import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.search.Sort;
import org.apache.solr.cloud.ActionThrottle;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
@@ -126,6 +127,13 @@ public abstract class SolrCoreState {
public abstract void rollbackIndexWriter(SolrCore core) throws IOException;
/**
+ * Get the current Sort of the current IndexWriter's MergePolicy..
+ *
+ * @throws IOException If there is a low-level I/O error.
+ */
+ public abstract Sort getMergePolicySort() throws IOException;
+
+ /**
* @return the {@link DirectoryFactory} that should be used.
*/
public abstract DirectoryFactory getDirectoryFactory();
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/test-files/solr/collection1/conf/solrconfig-sortingmergepolicyfactory.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-sortingmergepolicyfactory.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-sortingmergepolicyfactory.xml
new file mode 100644
index 0000000..a990719
--- /dev/null
+++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-sortingmergepolicyfactory.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" ?>
+
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<config>
+ <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+ <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
+ <schemaFactory class="ClassicIndexSchemaFactory"/>
+
+ <indexConfig>
+ <mergePolicyFactory class="org.apache.solr.index.SortingMergePolicyFactory">
+ <str name="wrapped.prefix">in</str>
+ <str name="in.class">org.apache.solr.util.RandomForceMergePolicyFactory</str>
+ <str name="sort">timestamp desc</str>
+ </mergePolicyFactory>
+ </indexConfig>
+
+ <requestHandler name="standard" class="solr.StandardRequestHandler"></requestHandler>
+
+ <updateHandler class="solr.DirectUpdateHandler2">
+ <updateLog>
+ <str name="dir">${solr.ulog.dir:}</str>
+ </updateLog>
+
+ <autoCommit>
+ <maxTime>${solr.autoCommit.maxTime:-1}</maxTime>
+ <openSearcher>false</openSearcher>
+ </autoCommit>
+
+ <autoSoftCommit>
+ <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime>
+ </autoSoftCommit>
+ </updateHandler>
+
+</config>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java
index 0830563..d90a0fc 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java
@@ -30,6 +30,7 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
+
import org.apache.lucene.util.LuceneTestCase;
import org.apache.lucene.util.LuceneTestCase.SuppressSysoutChecks;
import org.apache.solr.SolrTestCaseJ4;
@@ -451,4 +452,63 @@ public class TestMiniSolrCloudCluster extends LuceneTestCase {
}
}
+ @Test
+ public void testSegmentTerminateEarly() throws Exception {
+
+ final String collectionName = "testSegmentTerminateEarlyCollection";
+
+ final TestSegmentTerminateEarlyState tstes = new TestSegmentTerminateEarlyState();
+
+ File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
+ Builder jettyConfig = JettyConfig.builder();
+ jettyConfig.waitForLoadingCoresToFinish(null);
+ final MiniSolrCloudCluster miniCluster = createMiniSolrCloudCluster();
+ final CloudSolrClient cloudSolrClient = miniCluster.getSolrClient();
+ cloudSolrClient.setDefaultCollection(collectionName);
+
+ try {
+ // create collection
+ {
+ final String asyncId = (random().nextBoolean() ? null : "asyncId("+collectionName+".create)="+random().nextInt());
+ final Map<String, String> collectionProperties = new HashMap<>();
+ collectionProperties.put(CoreDescriptor.CORE_CONFIG, "solrconfig-sortingmergepolicyfactory.xml");
+ createCollection(miniCluster, collectionName, null, asyncId, Boolean.TRUE, collectionProperties);
+ if (asyncId != null) {
+ final RequestStatusState state = AbstractFullDistribZkTestBase.getRequestStateAfterCompletion(asyncId, 330, cloudSolrClient);
+ assertSame("did not see async createCollection completion", RequestStatusState.COMPLETED, state);
+ }
+ }
+
+ try (SolrZkClient zkClient = new SolrZkClient
+ (miniCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, 45000, null);
+ ZkStateReader zkStateReader = new ZkStateReader(zkClient)) {
+ AbstractDistribZkTestBase.waitForRecoveriesToFinish(collectionName, zkStateReader, true, true, 330);
+
+ // add some documents, then optimize to get merged-sorted segments
+ tstes.addDocuments(cloudSolrClient, 10, 10, true);
+
+ // CommonParams.SEGMENT_TERMINATE_EARLY parameter intentionally absent
+ tstes.queryTimestampDescending(cloudSolrClient);
+
+ // add a few more documents, but don't optimize to have some not-merge-sorted segments
+ tstes.addDocuments(cloudSolrClient, 2, 10, false);
+
+ // CommonParams.SEGMENT_TERMINATE_EARLY parameter now present
+ tstes.queryTimestampDescendingSegmentTerminateEarlyYes(cloudSolrClient);
+ tstes.queryTimestampDescendingSegmentTerminateEarlyNo(cloudSolrClient);
+
+ // CommonParams.SEGMENT_TERMINATE_EARLY parameter present but it won't be used
+ tstes.queryTimestampDescendingSegmentTerminateEarlyYesGrouped(cloudSolrClient);
+ tstes.queryTimestampAscendingSegmentTerminateEarlyYes(cloudSolrClient); // uses a sort order that is _not_ compatible with the merge sort order
+
+ // delete the collection we created earlier
+ miniCluster.deleteCollection(collectionName);
+ AbstractDistribZkTestBase.waitForCollectionToDisappear(collectionName, zkStateReader, true, true, 330);
+ }
+ }
+ finally {
+ miniCluster.shutdown();
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/test/org/apache/solr/cloud/TestSegmentTerminateEarlyState.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSegmentTerminateEarlyState.java b/solr/core/src/test/org/apache/solr/cloud/TestSegmentTerminateEarlyState.java
new file mode 100644
index 0000000..c9183dd
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSegmentTerminateEarlyState.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.cloud;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ShardParams;
+import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.response.SolrQueryResponse;
+
+class TestSegmentTerminateEarlyState {
+
+ final String keyField = "id";
+ final String timestampField = "timestamp";
+ final String oddField = "odd_l1"; // <dynamicField name="*_l1" type="long" indexed="true" stored="true" multiValued="false"/>
+ final String quadField = "quad_l1"; // <dynamicField name="*_l1" type="long" indexed="true" stored="true" multiValued="false"/>
+
+ final Set<Integer> minTimestampDocKeys = new HashSet<>();
+ final Set<Integer> maxTimestampDocKeys = new HashSet<>();
+
+ Integer minTimestampMM = null;
+ Integer maxTimestampMM = null;
+
+ int numDocs = 0;
+
+ void addDocuments(CloudSolrClient cloudSolrClient,
+ int numCommits, int numDocsPerCommit, boolean optimize) throws Exception {
+ for (int cc = 1; cc <= numCommits; ++cc) {
+ for (int nn = 1; nn <= numDocsPerCommit; ++nn) {
+ ++numDocs;
+ final Integer docKey = new Integer(numDocs);
+ SolrInputDocument doc = new SolrInputDocument();
+ doc.setField(keyField, ""+docKey);
+ final int MM = TestMiniSolrCloudCluster.random().nextInt(60);
+ if (minTimestampMM == null || MM <= minTimestampMM.intValue()) {
+ if (minTimestampMM != null && MM < minTimestampMM.intValue()) {
+ minTimestampDocKeys.clear();
+ }
+ minTimestampMM = new Integer(MM);
+ minTimestampDocKeys.add(docKey);
+ }
+ if (maxTimestampMM == null || maxTimestampMM.intValue() <= MM) {
+ if (maxTimestampMM != null && maxTimestampMM.intValue() < MM) {
+ maxTimestampDocKeys.clear();
+ }
+ maxTimestampMM = new Integer(MM);
+ maxTimestampDocKeys.add(docKey);
+ }
+ doc.setField(timestampField, "2016-01-01T00:"+MM+":00Z");
+ doc.setField(oddField, ""+(numDocs % 2));
+ doc.setField(quadField, ""+(numDocs % 4)+1);
+ cloudSolrClient.add(doc);
+ }
+ cloudSolrClient.commit();
+ }
+ if (optimize) {
+ cloudSolrClient.optimize();
+ }
+ }
+
+ void queryTimestampDescending(CloudSolrClient cloudSolrClient) throws Exception {
+ TestMiniSolrCloudCluster.assertFalse(maxTimestampDocKeys.isEmpty());
+ TestMiniSolrCloudCluster.assertTrue("numDocs="+numDocs+" is not even", (numDocs%2)==0);
+ final Long oddFieldValue = new Long(maxTimestampDocKeys.iterator().next().intValue()%2);
+ final SolrQuery query = new SolrQuery(oddField+":"+oddFieldValue);
+ query.setSort(timestampField, SolrQuery.ORDER.desc);
+ query.setFields(keyField, oddField, timestampField);
+ query.setRows(1);
+ // CommonParams.SEGMENT_TERMINATE_EARLY parameter intentionally absent
+ final QueryResponse rsp = cloudSolrClient.query(query);
+ // check correctness of the results count
+ TestMiniSolrCloudCluster.assertEquals("numFound", numDocs/2, rsp.getResults().getNumFound());
+ // check correctness of the first result
+ if (rsp.getResults().getNumFound() > 0) {
+ final SolrDocument solrDocument0 = rsp.getResults().get(0);
+ TestMiniSolrCloudCluster.assertTrue(keyField+" of ("+solrDocument0+") is not in maxTimestampDocKeys("+maxTimestampDocKeys+")",
+ maxTimestampDocKeys.contains(solrDocument0.getFieldValue(keyField)));
+ TestMiniSolrCloudCluster.assertEquals(oddField, oddFieldValue, solrDocument0.getFieldValue(oddField));
+ }
+ // check segmentTerminatedEarly flag
+ TestMiniSolrCloudCluster.assertNull("responseHeader.segmentTerminatedEarly present in "+rsp.getResponseHeader(),
+ rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY));
+ }
+
+ void queryTimestampDescendingSegmentTerminateEarlyYes(CloudSolrClient cloudSolrClient) throws Exception {
+ TestMiniSolrCloudCluster.assertFalse(maxTimestampDocKeys.isEmpty());
+ TestMiniSolrCloudCluster.assertTrue("numDocs="+numDocs+" is not even", (numDocs%2)==0);
+ final Long oddFieldValue = new Long(maxTimestampDocKeys.iterator().next().intValue()%2);
+ final SolrQuery query = new SolrQuery(oddField+":"+oddFieldValue);
+ query.setSort(timestampField, SolrQuery.ORDER.desc);
+ query.setFields(keyField, oddField, timestampField);
+ final int rowsWanted = 1;
+ query.setRows(rowsWanted);
+ final Boolean shardsInfoWanted = (TestMiniSolrCloudCluster.random().nextBoolean() ? null : new Boolean(TestMiniSolrCloudCluster.random().nextBoolean()));
+ if (shardsInfoWanted != null) {
+ query.set(ShardParams.SHARDS_INFO, shardsInfoWanted.booleanValue());
+ }
+ query.set(CommonParams.SEGMENT_TERMINATE_EARLY, true);
+ final QueryResponse rsp = cloudSolrClient.query(query);
+ // check correctness of the results count
+ TestMiniSolrCloudCluster.assertTrue("numFound", rowsWanted <= rsp.getResults().getNumFound());
+ TestMiniSolrCloudCluster.assertTrue("numFound", rsp.getResults().getNumFound() <= numDocs/2);
+ // check correctness of the first result
+ if (rsp.getResults().getNumFound() > 0) {
+ final SolrDocument solrDocument0 = rsp.getResults().get(0);
+ TestMiniSolrCloudCluster.assertTrue(keyField+" of ("+solrDocument0+") is not in maxTimestampDocKeys("+maxTimestampDocKeys+")",
+ maxTimestampDocKeys.contains(solrDocument0.getFieldValue(keyField)));
+ TestMiniSolrCloudCluster.assertEquals(oddField, oddFieldValue, rsp.getResults().get(0).getFieldValue(oddField));
+ }
+ // check segmentTerminatedEarly flag
+ TestMiniSolrCloudCluster.assertNotNull("responseHeader.segmentTerminatedEarly missing in "+rsp.getResponseHeader(),
+ rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY));
+ TestMiniSolrCloudCluster.assertTrue("responseHeader.segmentTerminatedEarly missing/false in "+rsp.getResponseHeader(),
+ Boolean.TRUE.equals(rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY)));
+ // check shards info
+ final Object shardsInfo = rsp.getResponse().get(ShardParams.SHARDS_INFO);
+ if (!Boolean.TRUE.equals(shardsInfoWanted)) {
+ TestMiniSolrCloudCluster.assertNull(ShardParams.SHARDS_INFO, shardsInfo);
+ } else {
+ TestMiniSolrCloudCluster.assertNotNull(ShardParams.SHARDS_INFO, shardsInfo);
+ int segmentTerminatedEarlyShardsCount = 0;
+ for (Map.Entry<String, ?> si : (SimpleOrderedMap<?>)shardsInfo) {
+ if (Boolean.TRUE.equals(((SimpleOrderedMap)si.getValue()).get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY))) {
+ segmentTerminatedEarlyShardsCount += 1;
+ }
+ }
+ // check segmentTerminatedEarly flag within shards info
+ TestMiniSolrCloudCluster.assertTrue(segmentTerminatedEarlyShardsCount+" shards reported "+SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY,
+ (0<segmentTerminatedEarlyShardsCount));
+ }
+ }
+
+ void queryTimestampDescendingSegmentTerminateEarlyNo(CloudSolrClient cloudSolrClient) throws Exception {
+ TestMiniSolrCloudCluster.assertFalse(maxTimestampDocKeys.isEmpty());
+ TestMiniSolrCloudCluster.assertTrue("numDocs="+numDocs+" is not even", (numDocs%2)==0);
+ final Long oddFieldValue = new Long(maxTimestampDocKeys.iterator().next().intValue()%2);
+ final SolrQuery query = new SolrQuery(oddField+":"+oddFieldValue);
+ query.setSort(timestampField, SolrQuery.ORDER.desc);
+ query.setFields(keyField, oddField, timestampField);
+ query.setRows(1);
+ final Boolean shardsInfoWanted = (TestMiniSolrCloudCluster.random().nextBoolean() ? null : new Boolean(TestMiniSolrCloudCluster.random().nextBoolean()));
+ if (shardsInfoWanted != null) {
+ query.set(ShardParams.SHARDS_INFO, shardsInfoWanted.booleanValue());
+ }
+ query.set(CommonParams.SEGMENT_TERMINATE_EARLY, false);
+ final QueryResponse rsp = cloudSolrClient.query(query);
+ // check correctness of the results count
+ TestMiniSolrCloudCluster.assertEquals("numFound", numDocs/2, rsp.getResults().getNumFound());
+ // check correctness of the first result
+ if (rsp.getResults().getNumFound() > 0) {
+ final SolrDocument solrDocument0 = rsp.getResults().get(0);
+ TestMiniSolrCloudCluster.assertTrue(keyField+" of ("+solrDocument0+") is not in maxTimestampDocKeys("+maxTimestampDocKeys+")",
+ maxTimestampDocKeys.contains(solrDocument0.getFieldValue(keyField)));
+ TestMiniSolrCloudCluster.assertEquals(oddField, oddFieldValue, rsp.getResults().get(0).getFieldValue(oddField));
+ }
+ // check segmentTerminatedEarly flag
+ TestMiniSolrCloudCluster.assertNull("responseHeader.segmentTerminatedEarly present in "+rsp.getResponseHeader(),
+ rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY));
+ TestMiniSolrCloudCluster.assertFalse("responseHeader.segmentTerminatedEarly present/true in "+rsp.getResponseHeader(),
+ Boolean.TRUE.equals(rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY)));
+ // check shards info
+ final Object shardsInfo = rsp.getResponse().get(ShardParams.SHARDS_INFO);
+ if (!Boolean.TRUE.equals(shardsInfoWanted)) {
+ TestMiniSolrCloudCluster.assertNull(ShardParams.SHARDS_INFO, shardsInfo);
+ } else {
+ TestMiniSolrCloudCluster.assertNotNull(ShardParams.SHARDS_INFO, shardsInfo);
+ int segmentTerminatedEarlyShardsCount = 0;
+ for (Map.Entry<String, ?> si : (SimpleOrderedMap<?>)shardsInfo) {
+ if (Boolean.TRUE.equals(((SimpleOrderedMap)si.getValue()).get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY))) {
+ segmentTerminatedEarlyShardsCount += 1;
+ }
+ }
+ TestMiniSolrCloudCluster.assertEquals("shards reporting "+SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY,
+ 0, segmentTerminatedEarlyShardsCount);
+ }
+ }
+
+ void queryTimestampDescendingSegmentTerminateEarlyYesGrouped(CloudSolrClient cloudSolrClient) throws Exception {
+ TestMiniSolrCloudCluster.assertFalse(maxTimestampDocKeys.isEmpty());
+ TestMiniSolrCloudCluster.assertTrue("numDocs="+numDocs+" is not even", (numDocs%2)==0);
+ final Long oddFieldValue = new Long(maxTimestampDocKeys.iterator().next().intValue()%2);
+ final SolrQuery query = new SolrQuery(oddField+":"+oddFieldValue);
+ query.setSort(timestampField, SolrQuery.ORDER.desc);
+ query.setFields(keyField, oddField, timestampField);
+ query.setRows(1);
+ query.set(CommonParams.SEGMENT_TERMINATE_EARLY, true);
+ TestMiniSolrCloudCluster.assertTrue("numDocs="+numDocs+" is not quad-able", (numDocs%4)==0);
+ query.add("group.field", quadField);
+ query.set("group", true);
+ final QueryResponse rsp = cloudSolrClient.query(query);
+ // check correctness of the results count
+ TestMiniSolrCloudCluster.assertEquals("matches", numDocs/2, rsp.getGroupResponse().getValues().get(0).getMatches());
+ // check correctness of the first result
+ if (rsp.getGroupResponse().getValues().get(0).getMatches() > 0) {
+ final SolrDocument solrDocument = rsp.getGroupResponse().getValues().get(0).getValues().get(0).getResult().get(0);
+ TestMiniSolrCloudCluster.assertTrue(keyField+" of ("+solrDocument+") is not in maxTimestampDocKeys("+maxTimestampDocKeys+")",
+ maxTimestampDocKeys.contains(solrDocument.getFieldValue(keyField)));
+ TestMiniSolrCloudCluster.assertEquals(oddField, oddFieldValue, solrDocument.getFieldValue(oddField));
+ }
+ // check segmentTerminatedEarly flag
+ // at present segmentTerminateEarly cannot be used with grouped queries
+ TestMiniSolrCloudCluster.assertFalse("responseHeader.segmentTerminatedEarly present/true in "+rsp.getResponseHeader(),
+ Boolean.TRUE.equals(rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY)));
+ }
+
+ void queryTimestampAscendingSegmentTerminateEarlyYes(CloudSolrClient cloudSolrClient) throws Exception {
+ TestMiniSolrCloudCluster.assertFalse(minTimestampDocKeys.isEmpty());
+ TestMiniSolrCloudCluster.assertTrue("numDocs="+numDocs+" is not even", (numDocs%2)==0);
+ final Long oddFieldValue = new Long(minTimestampDocKeys.iterator().next().intValue()%2);
+ final SolrQuery query = new SolrQuery(oddField+":"+oddFieldValue);
+ query.setSort(timestampField, SolrQuery.ORDER.asc); // a sort order that is _not_ compatible with the merge sort order
+ query.setFields(keyField, oddField, timestampField);
+ query.setRows(1);
+ query.set(CommonParams.SEGMENT_TERMINATE_EARLY, true);
+ final QueryResponse rsp = cloudSolrClient.query(query);
+ // check correctness of the results count
+ TestMiniSolrCloudCluster.assertEquals("numFound", numDocs/2, rsp.getResults().getNumFound());
+ // check correctness of the first result
+ if (rsp.getResults().getNumFound() > 0) {
+ final SolrDocument solrDocument0 = rsp.getResults().get(0);
+ TestMiniSolrCloudCluster.assertTrue(keyField+" of ("+solrDocument0+") is not in minTimestampDocKeys("+minTimestampDocKeys+")",
+ minTimestampDocKeys.contains(solrDocument0.getFieldValue(keyField)));
+ TestMiniSolrCloudCluster.assertEquals(oddField, oddFieldValue, solrDocument0.getFieldValue(oddField));
+ }
+ // check segmentTerminatedEarly flag
+ TestMiniSolrCloudCluster.assertNotNull("responseHeader.segmentTerminatedEarly missing in "+rsp.getResponseHeader(),
+ rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY));
+ // segmentTerminateEarly cannot be used with incompatible sort orders
+ TestMiniSolrCloudCluster.assertTrue("responseHeader.segmentTerminatedEarly missing/true in "+rsp.getResponseHeader(),
+ Boolean.FALSE.equals(rsp.getResponseHeader().get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY)));
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/test/org/apache/solr/response/TestSolrQueryResponse.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/response/TestSolrQueryResponse.java b/solr/core/src/test/org/apache/solr/response/TestSolrQueryResponse.java
index e938afc..8b17dc6 100644
--- a/solr/core/src/test/org/apache/solr/response/TestSolrQueryResponse.java
+++ b/solr/core/src/test/org/apache/solr/response/TestSolrQueryResponse.java
@@ -45,6 +45,12 @@ public class TestSolrQueryResponse extends LuceneTestCase {
}
@Test
+ public void testResponseHeaderSegmentTerminatedEarly() throws Exception {
+ assertEquals("SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY value changed",
+ "segmentTerminatedEarly", SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY);
+ }
+
+ @Test
public void testValues() throws Exception {
final SolrQueryResponse response = new SolrQueryResponse();
assertEquals("values initially not empty", 0, response.getValues().size());
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java b/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
index 4f413ee..ffb495e 100644
--- a/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
+++ b/solr/core/src/test/org/apache/solr/update/SolrIndexConfigTest.java
@@ -21,8 +21,12 @@ import java.util.Map;
import org.apache.lucene.index.ConcurrentMergeScheduler;
import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.MergePolicy;
import org.apache.lucene.index.SimpleMergedSegmentWarmer;
+import org.apache.lucene.index.SortingMergePolicy;
import org.apache.lucene.index.TieredMergePolicy;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.core.DirectoryFactory;
import org.apache.solr.core.SolrConfig;
@@ -44,6 +48,7 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
private static final String solrConfigFileNameWarmerRandomMergePolicyFactory = "solrconfig-warmer-randommergepolicyfactory.xml";
private static final String solrConfigFileNameTieredMergePolicy = "solrconfig-tieredmergepolicy.xml";
private static final String solrConfigFileNameTieredMergePolicyFactory = "solrconfig-tieredmergepolicyfactory.xml";
+ private static final String solrConfigFileNameSortingMergePolicyFactory = "solrconfig-sortingmergepolicyfactory.xml";
private static final String schemaFileName = "schema.xml";
@BeforeClass
@@ -91,6 +96,28 @@ public class SolrIndexConfigTest extends SolrTestCaseJ4 {
}
+ public void testSortingMPSolrIndexConfigCreation() throws Exception {
+ final String expectedFieldName = "timestamp";
+ final SortField.Type expectedFieldType = SortField.Type.LONG;
+ final boolean expectedFieldSortDescending = true;
+
+ SolrConfig solrConfig = new SolrConfig(instanceDir, solrConfigFileNameSortingMergePolicyFactory, null);
+ SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
+ assertNotNull(solrIndexConfig);
+ IndexSchema indexSchema = IndexSchemaFactory.buildIndexSchema(schemaFileName, solrConfig);
+
+ h.getCore().setLatestSchema(indexSchema);
+ IndexWriterConfig iwc = solrIndexConfig.toIndexWriterConfig(h.getCore());
+
+ final MergePolicy mergePolicy = iwc.getMergePolicy();
+ assertNotNull("null mergePolicy", mergePolicy);
+ assertTrue("mergePolicy ("+mergePolicy+") is not a SortingMergePolicy", mergePolicy instanceof SortingMergePolicy);
+ final SortingMergePolicy sortingMergePolicy = (SortingMergePolicy) mergePolicy;
+ final Sort expected = new Sort(new SortField(expectedFieldName, expectedFieldType, expectedFieldSortDescending));
+ final Sort actual = sortingMergePolicy.getSort();
+ assertEquals("SortingMergePolicy.getSort", expected, actual);
+ }
+
public void testMergedSegmentWarmerIndexConfigCreation() throws Exception {
SolrConfig solrConfig = new SolrConfig(instanceDir, random().nextBoolean() ? solrConfigFileNameWarmerRandomMergePolicy : solrConfigFileNameWarmerRandomMergePolicyFactory, null);
SolrIndexConfig solrIndexConfig = new SolrIndexConfig(solrConfig, null, null);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/67777908/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
index 5429328..5ccd70f 100644
--- a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
+++ b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
@@ -152,6 +152,12 @@ public interface CommonParams {
public static final String STREAM_CONTENTTYPE = "stream.contentType";
/**
+ * Whether or not the search may be terminated early within a segment.
+ */
+ public static final String SEGMENT_TERMINATE_EARLY = "segmentTerminateEarly";
+ public static final boolean SEGMENT_TERMINATE_EARLY_DEFAULT = false;
+
+ /**
* Timeout value in milliseconds. If not set, or the value is >= 0, there is no timeout.
*/
public static final String TIME_ALLOWED = "timeAllowed";