events = this.events.stream().filter(event -> event.v1() == false).map(Tuple::v2).collect(Collectors.toList());
+ return Collections.unmodifiableList(events);
+ }
+
+ public synchronized void reset() {
+ events.clear();
+ }
+
+}
diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java
index 4228c9fa699..fbb93202fcf 100644
--- a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java
+++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TasksIT.java
@@ -18,21 +18,277 @@
*/
package org.elasticsearch.action.admin.cluster.node.tasks;
+import org.elasticsearch.action.admin.cluster.health.ClusterHealthAction;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksAction;
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksResponse;
+import org.elasticsearch.action.admin.cluster.node.tasks.list.TaskInfo;
+import org.elasticsearch.action.admin.indices.refresh.RefreshAction;
+import org.elasticsearch.action.admin.indices.upgrade.post.UpgradeAction;
+import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryAction;
+import org.elasticsearch.action.percolate.PercolateAction;
+import org.elasticsearch.cluster.ClusterService;
+import org.elasticsearch.cluster.node.DiscoveryNode;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.collect.Tuple;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.tasks.MockTaskManager;
+import org.elasticsearch.test.transport.MockTransportService;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
/**
* Integration tests for task management API
+ *
+ * We need at least 2 nodes so we have a master node a non-master node
*/
-@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE)
+@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.SUITE, minNumDataNodes = 2)
public class TasksIT extends ESIntegTestCase {
+ private Map, RecordingTaskManagerListener> listeners = new HashMap<>();
+
+ @Override
+ protected Collection> nodePlugins() {
+ return pluginList(MockTransportService.TestPlugin.class);
+ }
+
+ @Override
+ protected Settings nodeSettings(int nodeOrdinal) {
+ return Settings.builder()
+ .put(super.nodeSettings(nodeOrdinal))
+ .put(MockTaskManager.USE_MOCK_TASK_MANAGER, true)
+ .build();
+ }
+
public void testTaskCounts() {
// Run only on data nodes
ListTasksResponse response = client().admin().cluster().prepareListTasks("data:true").setActions(ListTasksAction.NAME + "[n]").get();
assertThat(response.getTasks().size(), greaterThanOrEqualTo(cluster().numDataNodes()));
}
+
+ public void testMasterNodeOperationTasks() {
+ registerTaskManageListeners(ClusterHealthAction.NAME);
+
+ // First run the health on the master node - should produce only one task on the master node
+ internalCluster().masterClient().admin().cluster().prepareHealth().get();
+ assertEquals(1, numberOfEvents(ClusterHealthAction.NAME, Tuple::v1)); // counting only registration events
+ assertEquals(1, numberOfEvents(ClusterHealthAction.NAME, event -> event.v1() == false)); // counting only unregistration events
+
+ resetTaskManageListeners(ClusterHealthAction.NAME);
+
+ // Now run the health on a non-master node - should produce one task on master and one task on another node
+ internalCluster().nonMasterClient().admin().cluster().prepareHealth().get();
+ assertEquals(2, numberOfEvents(ClusterHealthAction.NAME, Tuple::v1)); // counting only registration events
+ assertEquals(2, numberOfEvents(ClusterHealthAction.NAME, event -> event.v1() == false)); // counting only unregistration events
+ List tasks = findEvents(ClusterHealthAction.NAME, Tuple::v1);
+
+ // Verify that one of these tasks is a parent of another task
+ if (tasks.get(0).getParentNode() == null) {
+ assertParentTask(Collections.singletonList(tasks.get(1)), tasks.get(0));
+ } else {
+ assertParentTask(Collections.singletonList(tasks.get(0)), tasks.get(1));
+ }
+ }
+
+ public void testTransportReplicationAllShardsTasks() {
+ registerTaskManageListeners(PercolateAction.NAME); // main task
+ registerTaskManageListeners(PercolateAction.NAME + "[s]"); // shard level tasks
+ createIndex("test");
+ ensureGreen("test"); // Make sure all shards are allocated
+ client().preparePercolate().setIndices("test").setDocumentType("foo").setSource("{}").get();
+
+ // the percolate operation should produce one main task
+ NumShards numberOfShards = getNumShards("test");
+ assertEquals(1, numberOfEvents(PercolateAction.NAME, Tuple::v1));
+ // and then one operation per shard
+ assertEquals(numberOfShards.totalNumShards, numberOfEvents(PercolateAction.NAME + "[s]", Tuple::v1));
+
+ // the shard level tasks should have the main task as a parent
+ assertParentTask(findEvents(PercolateAction.NAME + "[s]", Tuple::v1), findEvents(PercolateAction.NAME, Tuple::v1).get(0));
+ }
+
+ public void testTransportBroadcastByNodeTasks() {
+ registerTaskManageListeners(UpgradeAction.NAME); // main task
+ registerTaskManageListeners(UpgradeAction.NAME + "[n]"); // node level tasks
+ createIndex("test");
+ ensureGreen("test"); // Make sure all shards are allocated
+ client().admin().indices().prepareUpgrade("test").get();
+
+ // the percolate operation should produce one main task
+ assertEquals(1, numberOfEvents(UpgradeAction.NAME, Tuple::v1));
+ // and then one operation per each node where shards are located
+ assertEquals(internalCluster().nodesInclude("test").size(), numberOfEvents(UpgradeAction.NAME + "[n]", Tuple::v1));
+
+ // all node level tasks should have the main task as a parent
+ assertParentTask(findEvents(UpgradeAction.NAME + "[n]", Tuple::v1), findEvents(UpgradeAction.NAME, Tuple::v1).get(0));
+ }
+
+ public void testTransportReplicationSingleShardTasks() {
+ registerTaskManageListeners(ValidateQueryAction.NAME); // main task
+ registerTaskManageListeners(ValidateQueryAction.NAME + "[s]"); // shard level tasks
+ createIndex("test");
+ ensureGreen("test"); // Make sure all shards are allocated
+ client().admin().indices().prepareValidateQuery("test").get();
+
+ // the validate operation should produce one main task
+ assertEquals(1, numberOfEvents(ValidateQueryAction.NAME, Tuple::v1));
+ // and then one operation
+ assertEquals(1, numberOfEvents(ValidateQueryAction.NAME + "[s]", Tuple::v1));
+ // the shard level operation should have the main task as its parent
+ assertParentTask(findEvents(ValidateQueryAction.NAME + "[s]", Tuple::v1), findEvents(ValidateQueryAction.NAME, Tuple::v1).get(0));
+ }
+
+
+ public void testTransportBroadcastReplicationTasks() {
+ registerTaskManageListeners(RefreshAction.NAME); // main task
+ registerTaskManageListeners(RefreshAction.NAME + "[s]"); // shard level tasks
+ registerTaskManageListeners(RefreshAction.NAME + "[s][*]"); // primary and replica shard tasks
+ createIndex("test");
+ ensureGreen("test"); // Make sure all shards are allocated
+ client().admin().indices().prepareRefresh("test").get();
+
+ // the refresh operation should produce one main task
+ NumShards numberOfShards = getNumShards("test");
+
+ logger.debug("number of shards, total: [{}], primaries: [{}] ", numberOfShards.totalNumShards, numberOfShards.numPrimaries);
+ logger.debug("main events {}", numberOfEvents(RefreshAction.NAME, Tuple::v1));
+ logger.debug("main event node {}", findEvents(RefreshAction.NAME, Tuple::v1).get(0).getNode().name());
+ logger.debug("[s] events {}", numberOfEvents(RefreshAction.NAME + "[s]", Tuple::v1));
+ logger.debug("[s][*] events {}", numberOfEvents(RefreshAction.NAME + "[s][*]", Tuple::v1));
+ logger.debug("nodes with the index {}", internalCluster().nodesInclude("test"));
+
+ assertEquals(1, numberOfEvents(RefreshAction.NAME, Tuple::v1));
+ // Because it's broadcast replication action we will have as many [s] level requests
+ // as we have primary shards on the coordinating node plus we will have one task per primary outside of the
+ // coordinating node due to replication.
+ // If all primaries are on the coordinating node, the number of tasks should be equal to the number of primaries
+ // If all primaries are not on the coordinating node, the number of tasks should be equal to the number of primaries times 2
+ assertThat(numberOfEvents(RefreshAction.NAME + "[s]", Tuple::v1), greaterThanOrEqualTo(numberOfShards.numPrimaries));
+ assertThat(numberOfEvents(RefreshAction.NAME + "[s]", Tuple::v1), lessThanOrEqualTo(numberOfShards.numPrimaries * 2));
+
+ // Verify that all [s] events have the proper parent
+ // This is complicated because if the shard task runs on the same node it has main task as a parent
+ // but if it runs on non-coordinating node it would have another intermediate [s] task on the coordinating node as a parent
+ TaskInfo mainTask = findEvents(RefreshAction.NAME, Tuple::v1).get(0);
+ List sTasks = findEvents(RefreshAction.NAME + "[s]", Tuple::v1);
+ for (TaskInfo taskInfo : sTasks) {
+ if (mainTask.getNode().equals(taskInfo.getNode())) {
+ // This shard level task runs on the same node as a parent task - it should have the main task as a direct parent
+ assertParentTask(Collections.singletonList(taskInfo), mainTask);
+ } else {
+ String description = taskInfo.getDescription();
+ // This shard level task runs on another node - it should have a corresponding shard level task on the node where main task is running
+ List sTasksOnRequestingNode = findEvents(RefreshAction.NAME + "[s]",
+ event -> event.v1() && mainTask.getNode().equals(event.v2().getNode()) && description.equals(event.v2().getDescription()));
+ // There should be only one parent task
+ assertEquals(1, sTasksOnRequestingNode.size());
+ assertParentTask(Collections.singletonList(taskInfo), sTasksOnRequestingNode.get(0));
+ }
+ }
+
+ // we will have as many [s][p] and [s][r] tasks as we have primary and replica shards
+ assertEquals(numberOfShards.totalNumShards, numberOfEvents(RefreshAction.NAME + "[s][*]", Tuple::v1));
+
+ // we the [s][p] and [s][r] tasks should have a corresponding [s] task on the same node as a parent
+ List spEvents = findEvents(RefreshAction.NAME + "[s][*]", Tuple::v1);
+ for (TaskInfo taskInfo : spEvents) {
+ List sTask;
+ if (taskInfo.getAction().endsWith("[s][p]")) {
+ // A [s][p] level task should have a corresponding [s] level task on the same node
+ sTask = findEvents(RefreshAction.NAME + "[s]",
+ event -> event.v1() && taskInfo.getNode().equals(event.v2().getNode()) && taskInfo.getDescription().equals(event.v2().getDescription()));
+ } else {
+ // A [s][r] level task should have a corresponding [s] level task on the a different node (where primary is located)
+ sTask = findEvents(RefreshAction.NAME + "[s]",
+ event -> event.v1() && taskInfo.getParentNode().equals(event.v2().getNode().getId()) && taskInfo.getDescription().equals(event.v2().getDescription()));
+ }
+ // There should be only one parent task
+ assertEquals(1, sTask.size());
+ assertParentTask(Collections.singletonList(taskInfo), sTask.get(0));
+ }
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ for (Map.Entry, RecordingTaskManagerListener> entry : listeners.entrySet()) {
+ ((MockTaskManager)internalCluster().getInstance(ClusterService.class, entry.getKey().v1()).getTaskManager()).removeListener(entry.getValue());
+ }
+ listeners.clear();
+ super.tearDown();
+ }
+
+ /**
+ * Registers recording task event listeners with the given action mask on all nodes
+ */
+ private void registerTaskManageListeners(String actionMasks) {
+ for (ClusterService clusterService : internalCluster().getInstances(ClusterService.class)) {
+ DiscoveryNode node = clusterService.localNode();
+ RecordingTaskManagerListener listener = new RecordingTaskManagerListener(node, Strings.splitStringToArray(actionMasks, ','));
+ ((MockTaskManager)clusterService.getTaskManager()).addListener(listener);
+ RecordingTaskManagerListener oldListener = listeners.put(new Tuple<>(node.name(), actionMasks), listener);
+ assertNull(oldListener);
+ }
+ }
+
+ /**
+ * Resets all recording task event listeners with the given action mask on all nodes
+ */
+ private void resetTaskManageListeners(String actionMasks) {
+ for (Map.Entry, RecordingTaskManagerListener> entry : listeners.entrySet()) {
+ if (actionMasks == null || entry.getKey().v2().equals(actionMasks)) {
+ entry.getValue().reset();
+ }
+ }
+ }
+
+ /**
+ * Returns the number of events that satisfy the criteria across all nodes
+ *
+ * @param actionMasks action masks to match
+ * @return number of events that satisfy the criteria
+ */
+ private int numberOfEvents(String actionMasks, Function, Boolean> criteria) {
+ return findEvents(actionMasks, criteria).size();
+ }
+
+ /**
+ * Returns all events that satisfy the criteria across all nodes
+ *
+ * @param actionMasks action masks to match
+ * @return number of events that satisfy the criteria
+ */
+ private List findEvents(String actionMasks, Function, Boolean> criteria) {
+ List events = new ArrayList<>();
+ for (Map.Entry, RecordingTaskManagerListener> entry : listeners.entrySet()) {
+ if (actionMasks == null || entry.getKey().v2().equals(actionMasks)) {
+ for (Tuple taskEvent : entry.getValue().getEvents()) {
+ if (criteria.apply(taskEvent)) {
+ events.add(taskEvent.v2());
+ }
+ }
+ }
+ }
+ return events;
+ }
+
+ /**
+ * Asserts that all tasks in the tasks list have the same parentTask
+ */
+ private void assertParentTask(List tasks, TaskInfo parentTask) {
+ for (TaskInfo task : tasks) {
+ assertNotNull(task.getParentNode());
+ assertEquals(parentTask.getNode().getId(), task.getParentNode());
+ assertEquals(parentTask.getId(), task.getParentId());
+ }
+ }
}
diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TransportTasksActionTests.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TransportTasksActionTests.java
index 3fbac003419..4e1c08261a3 100644
--- a/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TransportTasksActionTests.java
+++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/node/tasks/TransportTasksActionTests.java
@@ -48,10 +48,11 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.lease.Releasable;
import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.tasks.ChildTask;
import org.elasticsearch.tasks.Task;
+import org.elasticsearch.tasks.TaskManager;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.cluster.TestClusterService;
+import org.elasticsearch.test.tasks.MockTaskManager;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.local.LocalTransport;
@@ -95,12 +96,11 @@ public class TransportTasksActionTests extends ESTestCase {
threadPool = null;
}
- @Before
- public final void setupTestNodes() throws Exception {
+ public void setupTestNodes(Settings settings) {
nodesCount = randomIntBetween(2, 10);
testNodes = new TestNode[nodesCount];
for (int i = 0; i < testNodes.length; i++) {
- testNodes[i] = new TestNode("node" + i, threadPool, Settings.EMPTY);
+ testNodes[i] = new TestNode("node" + i, threadPool, settings);
}
}
@@ -113,11 +113,20 @@ public class TransportTasksActionTests extends ESTestCase {
private static class TestNode implements Releasable {
public TestNode(String name, ThreadPool threadPool, Settings settings) {
- clusterService = new TestClusterService(threadPool);
- transportService = new TransportService(Settings.EMPTY,
- new LocalTransport(Settings.EMPTY, threadPool, Version.CURRENT, new NamedWriteableRegistry()),
- threadPool);
+ transportService = new TransportService(settings,
+ new LocalTransport(settings, threadPool, Version.CURRENT, new NamedWriteableRegistry()),
+ threadPool){
+ @Override
+ protected TaskManager createTaskManager() {
+ if (settings.getAsBoolean(MockTaskManager.USE_MOCK_TASK_MANAGER, false)) {
+ return new MockTaskManager(settings);
+ } else {
+ return super.createTaskManager();
+ }
+ }
+ };
transportService.start();
+ clusterService = new TestClusterService(threadPool, transportService);
discoveryNode = new DiscoveryNode(name, transportService.boundAddress().publishAddress(), Version.CURRENT);
transportListTasksAction = new TransportListTasksAction(settings, clusterName, threadPool, clusterService, transportService,
new ActionFilters(Collections.emptySet()), new IndexNameExpressionResolver(settings));
@@ -150,6 +159,15 @@ public class TransportTasksActionTests extends ESTestCase {
}
}
+ public static RecordingTaskManagerListener[] setupListeners(TestNode[] nodes, String... actionMasks) {
+ RecordingTaskManagerListener[] listeners = new RecordingTaskManagerListener[nodes.length];
+ for (int i = 0; i < nodes.length; i++) {
+ listeners[i] = new RecordingTaskManagerListener(nodes[i].discoveryNode, actionMasks);
+ ((MockTaskManager)(nodes[i].clusterService.getTaskManager())).addListener(listeners[i]);
+ }
+ return listeners;
+ }
+
public static class NodeRequest extends BaseNodeRequest {
protected String requestName;
private boolean enableTaskManager;
@@ -180,7 +198,7 @@ public class TransportTasksActionTests extends ESTestCase {
@Override
public String getDescription() {
- return "NodeRequest[" + requestName + ", " + enableTaskManager + "]";
+ return "NodeRequest[" + requestName + ", " + enableTaskManager + "]";
}
@Override
@@ -464,6 +482,7 @@ public class TransportTasksActionTests extends ESTestCase {
}
public void testRunningTasksCount() throws Exception {
+ setupTestNodes(Settings.EMPTY);
connectNodes(testNodes);
CountDownLatch checkLatch = new CountDownLatch(1);
CountDownLatch responseLatch = new CountDownLatch(1);
@@ -553,6 +572,7 @@ public class TransportTasksActionTests extends ESTestCase {
}
public void testFindChildTasks() throws Exception {
+ setupTestNodes(Settings.EMPTY);
connectNodes(testNodes);
CountDownLatch checkLatch = new CountDownLatch(1);
ActionFuture future = startBlockingTestNodesAction(checkLatch);
@@ -586,10 +606,11 @@ public class TransportTasksActionTests extends ESTestCase {
}
public void testTaskManagementOptOut() throws Exception {
+ setupTestNodes(Settings.EMPTY);
connectNodes(testNodes);
CountDownLatch checkLatch = new CountDownLatch(1);
// Starting actions that disable task manager
- ActionFuture future = startBlockingTestNodesAction(checkLatch, new NodesRequest("Test Request", false));
+ ActionFuture future = startBlockingTestNodesAction(checkLatch, new NodesRequest("Test Request", false));
TestNode testNode = testNodes[randomIntBetween(0, testNodes.length - 1)];
@@ -606,6 +627,7 @@ public class TransportTasksActionTests extends ESTestCase {
}
public void testTasksDescriptions() throws Exception {
+ setupTestNodes(Settings.EMPTY);
connectNodes(testNodes);
CountDownLatch checkLatch = new CountDownLatch(1);
ActionFuture future = startBlockingTestNodesAction(checkLatch);
@@ -637,8 +659,11 @@ public class TransportTasksActionTests extends ESTestCase {
}
public void testFailedTasksCount() throws ExecutionException, InterruptedException, IOException {
+ Settings settings = Settings.builder().put(MockTaskManager.USE_MOCK_TASK_MANAGER, true).build();
+ setupTestNodes(settings);
connectNodes(testNodes);
TestNodesAction[] actions = new TestNodesAction[nodesCount];
+ RecordingTaskManagerListener[] listeners = setupListeners(testNodes, "testAction*");
for (int i = 0; i < testNodes.length; i++) {
final int node = i;
actions[i] = new TestNodesAction(Settings.EMPTY, "testAction", clusterName, threadPool, testNodes[i].clusterService, testNodes[i].transportService) {
@@ -656,9 +681,21 @@ public class TransportTasksActionTests extends ESTestCase {
NodesRequest request = new NodesRequest("Test Request");
NodesResponse responses = actions[0].execute(request).get();
assertEquals(nodesCount, responses.failureCount());
+
+ // Make sure that actions are still registered in the task manager on all nodes
+ // Twice on the coordinating node and once on all other nodes.
+ assertEquals(4, listeners[0].getEvents().size());
+ assertEquals(2, listeners[0].getRegistrationEvents().size());
+ assertEquals(2, listeners[0].getUnregistrationEvents().size());
+ for (int i = 1; i < listeners.length; i++) {
+ assertEquals(2, listeners[i].getEvents().size());
+ assertEquals(1, listeners[i].getRegistrationEvents().size());
+ assertEquals(1, listeners[i].getUnregistrationEvents().size());
+ }
}
public void testTaskLevelActionFailures() throws ExecutionException, InterruptedException, IOException {
+ setupTestNodes(Settings.EMPTY);
connectNodes(testNodes);
CountDownLatch checkLatch = new CountDownLatch(1);
ActionFuture future = startBlockingTestNodesAction(checkLatch);
@@ -672,7 +709,7 @@ public class TransportTasksActionTests extends ESTestCase {
@Override
protected TestTaskResponse taskOperation(TestTasksRequest request, Task task) {
logger.info("Task action on node " + node);
- if (failTaskOnNode == node && ((ChildTask) task).getParentNode() != null) {
+ if (failTaskOnNode == node && task.getParentNode() != null) {
logger.info("Failing on node " + node);
throw new RuntimeException("Task level failure");
}
diff --git a/core/src/test/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeActionTests.java b/core/src/test/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeActionTests.java
index 76307ccd806..a408ccc5bf9 100644
--- a/core/src/test/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeActionTests.java
+++ b/core/src/test/java/org/elasticsearch/action/support/broadcast/node/TransportBroadcastByNodeActionTests.java
@@ -242,7 +242,7 @@ public class TransportBroadcastByNodeActionTests extends ESTestCase {
.addGlobalBlock(new ClusterBlock(1, "test-block", false, true, RestStatus.SERVICE_UNAVAILABLE, ClusterBlockLevel.ALL));
clusterService.setState(ClusterState.builder(clusterService.state()).blocks(block));
try {
- action.new AsyncAction(request, listener).start();
+ action.new AsyncAction(null, request, listener).start();
fail("expected ClusterBlockException");
} catch (ClusterBlockException expected) {
assertEquals("blocked by: [SERVICE_UNAVAILABLE/1/test-block];", expected.getMessage());
@@ -257,7 +257,7 @@ public class TransportBroadcastByNodeActionTests extends ESTestCase {
.addIndexBlock(TEST_INDEX, new ClusterBlock(1, "test-block", false, true, RestStatus.SERVICE_UNAVAILABLE, ClusterBlockLevel.ALL));
clusterService.setState(ClusterState.builder(clusterService.state()).blocks(block));
try {
- action.new AsyncAction(request, listener).start();
+ action.new AsyncAction(null, request, listener).start();
fail("expected ClusterBlockException");
} catch (ClusterBlockException expected) {
assertEquals("blocked by: [SERVICE_UNAVAILABLE/1/test-block];", expected.getMessage());
@@ -268,7 +268,7 @@ public class TransportBroadcastByNodeActionTests extends ESTestCase {
Request request = new Request(new String[]{TEST_INDEX});
PlainActionFuture listener = new PlainActionFuture<>();
- action.new AsyncAction(request, listener).start();
+ action.new AsyncAction(null, request, listener).start();
Map> capturedRequests = transport.getCapturedRequestsByTargetNodeAndClear();
ShardsIterator shardIt = clusterService.state().routingTable().allShards(new String[]{TEST_INDEX});
@@ -302,7 +302,7 @@ public class TransportBroadcastByNodeActionTests extends ESTestCase {
clusterService.setState(ClusterState.builder(clusterService.state()).nodes(builder));
- action.new AsyncAction(request, listener).start();
+ action.new AsyncAction(null, request, listener).start();
Map> capturedRequests = transport.getCapturedRequestsByTargetNodeAndClear();
@@ -389,7 +389,7 @@ public class TransportBroadcastByNodeActionTests extends ESTestCase {
clusterService.setState(ClusterState.builder(clusterService.state()).nodes(builder));
}
- action.new AsyncAction(request, listener).start();
+ action.new AsyncAction(null, request, listener).start();
Map> capturedRequests = transport.getCapturedRequestsByTargetNodeAndClear();
ShardsIterator shardIt = clusterService.state().getRoutingTable().allShards(new String[]{TEST_INDEX});
diff --git a/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java b/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java
index fccdd494af7..7b9fd91a567 100644
--- a/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java
+++ b/core/src/test/java/org/elasticsearch/action/support/replication/BroadcastReplicationTests.java
@@ -41,6 +41,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.tasks.Task;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.cluster.TestClusterService;
import org.elasticsearch.threadpool.ThreadPool;
@@ -207,7 +208,7 @@ public class BroadcastReplicationTests extends ESTestCase {
}
@Override
- protected void shardExecute(DummyBroadcastRequest request, ShardId shardId, ActionListener shardActionListener) {
+ protected void shardExecute(Task task, DummyBroadcastRequest request, ShardId shardId, ActionListener shardActionListener) {
capturedShardRequests.add(new Tuple<>(shardId, shardActionListener));
}
}
diff --git a/core/src/test/java/org/elasticsearch/action/support/replication/TransportReplicationActionTests.java b/core/src/test/java/org/elasticsearch/action/support/replication/TransportReplicationActionTests.java
index c868b0d036f..402a454649b 100644
--- a/core/src/test/java/org/elasticsearch/action/support/replication/TransportReplicationActionTests.java
+++ b/core/src/test/java/org/elasticsearch/action/support/replication/TransportReplicationActionTests.java
@@ -140,7 +140,7 @@ public class TransportReplicationActionTests extends ESTestCase {
ClusterBlocks.Builder block = ClusterBlocks.builder()
.addGlobalBlock(new ClusterBlock(1, "non retryable", false, true, RestStatus.SERVICE_UNAVAILABLE, ClusterBlockLevel.ALL));
clusterService.setState(ClusterState.builder(clusterService.state()).blocks(block));
- TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(request, listener);
+ TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(null, request, listener);
reroutePhase.run();
assertListenerThrows("primary phase should fail operation", listener, ClusterBlockException.class);
@@ -148,13 +148,13 @@ public class TransportReplicationActionTests extends ESTestCase {
.addGlobalBlock(new ClusterBlock(1, "retryable", true, true, RestStatus.SERVICE_UNAVAILABLE, ClusterBlockLevel.ALL));
clusterService.setState(ClusterState.builder(clusterService.state()).blocks(block));
listener = new PlainActionFuture<>();
- reroutePhase = action.new ReroutePhase(new Request().timeout("5ms"), listener);
+ reroutePhase = action.new ReroutePhase(null, new Request().timeout("5ms"), listener);
reroutePhase.run();
assertListenerThrows("failed to timeout on retryable block", listener, ClusterBlockException.class);
listener = new PlainActionFuture<>();
- reroutePhase = action.new ReroutePhase(new Request(), listener);
+ reroutePhase = action.new ReroutePhase(null, new Request(), listener);
reroutePhase.run();
assertFalse("primary phase should wait on retryable block", listener.isDone());
@@ -180,13 +180,13 @@ public class TransportReplicationActionTests extends ESTestCase {
Request request = new Request(shardId).timeout("1ms");
PlainActionFuture listener = new PlainActionFuture<>();
- TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(request, listener);
+ TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(null, request, listener);
reroutePhase.run();
assertListenerThrows("unassigned primary didn't cause a timeout", listener, UnavailableShardsException.class);
request = new Request(shardId);
listener = new PlainActionFuture<>();
- reroutePhase = action.new ReroutePhase(request, listener);
+ reroutePhase = action.new ReroutePhase(null, request, listener);
reroutePhase.run();
assertFalse("unassigned primary didn't cause a retry", listener.isDone());
@@ -211,12 +211,12 @@ public class TransportReplicationActionTests extends ESTestCase {
logger.debug("--> using initial state:\n{}", clusterService.state().prettyPrint());
Request request = new Request(new ShardId("unknown_index", "_na_", 0)).timeout("1ms");
PlainActionFuture listener = new PlainActionFuture<>();
- TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(request, listener);
+ TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(null, request, listener);
reroutePhase.run();
assertListenerThrows("must throw index not found exception", listener, IndexNotFoundException.class);
request = new Request(new ShardId(index, "_na_", 10)).timeout("1ms");
listener = new PlainActionFuture<>();
- reroutePhase = action.new ReroutePhase(request, listener);
+ reroutePhase = action.new ReroutePhase(null, request, listener);
reroutePhase.run();
assertListenerThrows("must throw shard not found exception", listener, ShardNotFoundException.class);
}
@@ -234,7 +234,7 @@ public class TransportReplicationActionTests extends ESTestCase {
Request request = new Request(shardId);
PlainActionFuture listener = new PlainActionFuture<>();
- TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(request, listener);
+ TransportReplicationAction.ReroutePhase reroutePhase = action.new ReroutePhase(null, request, listener);
reroutePhase.run();
assertThat(request.shardId(), equalTo(shardId));
logger.info("--> primary is assigned to [{}], checking request forwarded", primaryNodeId);
diff --git a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java
index 9a3a4632c6f..b5cd130e191 100644
--- a/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java
+++ b/modules/lang-groovy/src/test/java/org/elasticsearch/messy/tests/IndicesRequestTests.java
@@ -92,6 +92,7 @@ import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.groovy.GroovyPlugin;
import org.elasticsearch.search.action.SearchServiceTransportAction;
+import org.elasticsearch.tasks.Task;
import org.elasticsearch.tasks.TaskManager;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
@@ -821,7 +822,7 @@ public class IndicesRequestTests extends ESIntegTestCase {
}
@Override
- public void messageReceived(T request, TransportChannel channel) throws Exception {
+ public void messageReceived(T request, TransportChannel channel, Task task) throws Exception {
synchronized (InterceptingTransportService.this) {
if (actions.contains(action)) {
List requestList = requests.get(action);
@@ -834,7 +835,12 @@ public class IndicesRequestTests extends ESIntegTestCase {
}
}
}
- requestHandler.messageReceived(request, channel);
+ requestHandler.messageReceived(request, channel, task);
+ }
+
+ @Override
+ public void messageReceived(T request, TransportChannel channel) throws Exception {
+ messageReceived(request, channel, null);
}
}
}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/cluster/TestClusterService.java b/test/framework/src/main/java/org/elasticsearch/test/cluster/TestClusterService.java
index 92b5f9a584b..172c746e88e 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/cluster/TestClusterService.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/cluster/TestClusterService.java
@@ -49,6 +49,7 @@ import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.common.util.concurrent.FutureUtils;
import org.elasticsearch.tasks.TaskManager;
import org.elasticsearch.threadpool.ThreadPool;
+import org.elasticsearch.transport.TransportService;
import java.util.Arrays;
import java.util.Iterator;
@@ -77,6 +78,11 @@ public class TestClusterService implements ClusterService {
taskManager = new TaskManager(Settings.EMPTY);
}
+ public TestClusterService(ThreadPool threadPool, TransportService transportService) {
+ this(ClusterState.builder(new ClusterName("test")).build(), threadPool);
+ taskManager = transportService.getTaskManager();
+ }
+
public TestClusterService(ClusterState state) {
this(state, null);
}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java
new file mode 100644
index 00000000000..9b6bc72162c
--- /dev/null
+++ b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManager.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.test.tasks;
+
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.tasks.Task;
+import org.elasticsearch.tasks.TaskManager;
+import org.elasticsearch.transport.TransportRequest;
+
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * A mock task manager that allows adding listeners for events
+ */
+public class MockTaskManager extends TaskManager {
+
+ public static final String USE_MOCK_TASK_MANAGER = "tests.mock.taskmanager.enabled";
+
+ private final Collection listeners = new CopyOnWriteArrayList<>();
+
+ public MockTaskManager(Settings settings) {
+ super(settings);
+ }
+
+ @Override
+ public Task register(String type, String action, TransportRequest request) {
+ Task task = super.register(type, action, request);
+ if (task != null) {
+ for (MockTaskManagerListener listener : listeners) {
+ try {
+ listener.onTaskRegistered(task);
+ } catch (Throwable t) {
+ logger.warn("failed to notify task manager listener about unregistering the task with id {}", t, task.getId());
+ }
+ }
+ }
+ return task;
+ }
+
+ @Override
+ public Task unregister(Task task) {
+ Task removedTask = super.unregister(task);
+ if (removedTask != null) {
+ for (MockTaskManagerListener listener : listeners) {
+ try {
+ listener.onTaskUnregistered(task);
+ } catch (Throwable t) {
+ logger.warn("failed to notify task manager listener about unregistering the task with id {}", t, task.getId());
+ }
+ }
+ } else {
+ logger.warn("trying to remove the same with id {} twice", task.getId());
+ }
+ return removedTask;
+ }
+
+ public void addListener(MockTaskManagerListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(MockTaskManagerListener listener) {
+ listeners.remove(listener);
+ }
+}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java
new file mode 100644
index 00000000000..d10dd357999
--- /dev/null
+++ b/test/framework/src/main/java/org/elasticsearch/test/tasks/MockTaskManagerListener.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.test.tasks;
+
+import org.elasticsearch.tasks.Task;
+
+/**
+ * Listener for task registration/unregistration
+ */
+public interface MockTaskManagerListener {
+ void onTaskRegistered(Task task);
+
+ void onTaskUnregistered(Task task);
+}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java
index 985c8a86838..84c981d60d5 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/transport/MockTransportService.java
@@ -34,6 +34,8 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.tasks.TaskManager;
+import org.elasticsearch.test.tasks.MockTaskManager;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.ConnectTransportException;
import org.elasticsearch.transport.RequestHandlerRegistry;
@@ -100,6 +102,15 @@ public class MockTransportService extends TransportService {
return transportAddresses.toArray(new TransportAddress[transportAddresses.size()]);
}
+ @Override
+ protected TaskManager createTaskManager() {
+ if (settings.getAsBoolean(MockTaskManager.USE_MOCK_TASK_MANAGER, false)) {
+ return new MockTaskManager(settings);
+ } else {
+ return super.createTaskManager();
+ }
+ }
+
/**
* Clears all the registered rules.
*/
From e3816d58aeb8ee750e0ada6ac97f379b7f3578b3 Mon Sep 17 00:00:00 2001
From: Ali Beyad
Date: Thu, 28 Jan 2016 17:10:04 -0500
Subject: [PATCH 08/11] TribeIT.testOnConflictDrop test awaits fix until #16299
is resolved
---
core/src/test/java/org/elasticsearch/tribe/TribeIT.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/core/src/test/java/org/elasticsearch/tribe/TribeIT.java b/core/src/test/java/org/elasticsearch/tribe/TribeIT.java
index 260c6252efd..506321684ba 100644
--- a/core/src/test/java/org/elasticsearch/tribe/TribeIT.java
+++ b/core/src/test/java/org/elasticsearch/tribe/TribeIT.java
@@ -225,6 +225,7 @@ public class TribeIT extends ESIntegTestCase {
}
}
+ @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/16299")
public void testOnConflictDrop() throws Exception {
logger.info("create 2 indices, test1 on t1, and test2 on t2");
assertAcked(cluster().client().admin().indices().prepareCreate("conflict"));
From 9ec1b11148fe2a347c31f64d6630a42fffbef763 Mon Sep 17 00:00:00 2001
From: Martijn van Groningen
Date: Thu, 28 Jan 2016 10:31:43 +0100
Subject: [PATCH 09/11] term vectors: The term vector APIs no longer modify the
mappings if an unmapped field is found
---
.../index/termvectors/TermVectorsService.java | 9 +---
.../action/termvectors/GetTermVectorsIT.java | 47 -------------------
docs/reference/migration/migrate_3_0.asciidoc | 6 +++
3 files changed, 7 insertions(+), 55 deletions(-)
diff --git a/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java b/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
index fbc18fd578a..c78d125ab46 100644
--- a/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
+++ b/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
@@ -71,12 +71,10 @@ import static org.elasticsearch.index.mapper.SourceToParse.source;
public class TermVectorsService {
- private final MappingUpdatedAction mappingUpdatedAction;
private final TransportDfsOnlyAction dfsAction;
@Inject
- public TermVectorsService(MappingUpdatedAction mappingUpdatedAction, TransportDfsOnlyAction dfsAction) {
- this.mappingUpdatedAction = mappingUpdatedAction;
+ public TermVectorsService(TransportDfsOnlyAction dfsAction) {
this.dfsAction = dfsAction;
}
@@ -293,16 +291,11 @@ public class TermVectorsService {
private ParsedDocument parseDocument(IndexShard indexShard, String index, String type, BytesReference doc) throws Throwable {
MapperService mapperService = indexShard.mapperService();
-
- // TODO: make parsing not dynamically create fields not in the original mapping
DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(type);
ParsedDocument parsedDocument = docMapper.getDocumentMapper().parse(source(doc).index(index).type(type).flyweight(true));
if (docMapper.getMapping() != null) {
parsedDocument.addDynamicMappingsUpdate(docMapper.getMapping());
}
- if (parsedDocument.dynamicMappingsUpdate() != null) {
- mappingUpdatedAction.updateMappingOnMasterSynchronously(index, type, parsedDocument.dynamicMappingsUpdate());
- }
return parsedDocument;
}
diff --git a/core/src/test/java/org/elasticsearch/action/termvectors/GetTermVectorsIT.java b/core/src/test/java/org/elasticsearch/action/termvectors/GetTermVectorsIT.java
index 16fd9f4b718..45b045a7f4b 100644
--- a/core/src/test/java/org/elasticsearch/action/termvectors/GetTermVectorsIT.java
+++ b/core/src/test/java/org/elasticsearch/action/termvectors/GetTermVectorsIT.java
@@ -870,53 +870,6 @@ public class GetTermVectorsIT extends AbstractTermVectorsTestCase {
checkBrownFoxTermVector(resp.getFields(), "field1", false);
}
- public void testArtificialNonExistingField() throws Exception {
- // setup indices
- Settings.Builder settings = settingsBuilder()
- .put(indexSettings())
- .put("index.analysis.analyzer", "standard");
- assertAcked(prepareCreate("test")
- .setSettings(settings)
- .addMapping("type1", "field1", "type=string"));
- ensureGreen();
-
- // index just one doc
- List indexBuilders = new ArrayList<>();
- indexBuilders.add(client().prepareIndex()
- .setIndex("test")
- .setType("type1")
- .setId("1")
- .setRouting("1")
- .setSource("field1", "some text"));
- indexRandom(true, indexBuilders);
-
- // request tvs from artificial document
- XContentBuilder doc = jsonBuilder()
- .startObject()
- .field("field1", "the quick brown fox jumps over the lazy dog")
- .field("non_existing", "the quick brown fox jumps over the lazy dog")
- .endObject();
-
- for (int i = 0; i < 2; i++) {
- TermVectorsResponse resp = client().prepareTermVectors()
- .setIndex("test")
- .setType("type1")
- .setDoc(doc)
- .setRouting("" + i)
- .setOffsets(true)
- .setPositions(true)
- .setFieldStatistics(true)
- .setTermStatistics(true)
- .get();
- assertThat(resp.isExists(), equalTo(true));
- checkBrownFoxTermVector(resp.getFields(), "field1", false);
- // we should have created a mapping for this field
- assertMappingOnMaster("test", "type1", "non_existing");
- // and return the generated term vectors
- checkBrownFoxTermVector(resp.getFields(), "non_existing", false);
- }
- }
-
public void testPerFieldAnalyzer() throws IOException {
int numFields = 25;
diff --git a/docs/reference/migration/migrate_3_0.asciidoc b/docs/reference/migration/migrate_3_0.asciidoc
index 067932ca21f..78f8ff40307 100644
--- a/docs/reference/migration/migrate_3_0.asciidoc
+++ b/docs/reference/migration/migrate_3_0.asciidoc
@@ -18,6 +18,7 @@ your application to Elasticsearch 3.0.
* <>
* <>
* <>
+* <>
[[breaking_30_search_changes]]
=== Warmers
@@ -707,3 +708,8 @@ Previously script mode settings (e.g., "script.inline: true",
values `off`, `false`, `0`, and `no` for disabling a scripting mode.
The variants `on`, `1`, and `yes ` for enabling and `off`, `0`,
and `no` for disabling are no longer supported.
+
+[[breaking_30_term_vectors]]
+=== Term vectors
+
+The term vectors APIs no longer persist unmapped fields in the mappings.
From f5e89f724281dd8d20e4fcbebeb29e2885d095bc Mon Sep 17 00:00:00 2001
From: Martijn van Groningen
Date: Thu, 28 Jan 2016 10:15:04 +0100
Subject: [PATCH 10/11] mappings: remove fly weight
---
.../index/mapper/ParseContext.java | 13 +---------
.../index/mapper/SourceToParse.java | 11 ---------
.../index/mapper/internal/IdFieldMapper.java | 2 +-
.../mapper/internal/ParentFieldMapper.java | 4 +---
.../mapper/internal/SourceFieldMapper.java | 5 ++--
.../index/mapper/internal/TTLFieldMapper.java | 2 +-
.../index/mapper/internal/UidFieldMapper.java | 2 +-
.../percolator/PercolatorFieldMapper.java | 4 +---
.../index/termvectors/TermVectorsService.java | 2 +-
.../percolator/PercolateDocumentParser.java | 24 +++++++++----------
.../index/mapper/size/SizeFieldMapper.java | 2 +-
11 files changed, 22 insertions(+), 49 deletions(-)
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ParseContext.java b/core/src/main/java/org/elasticsearch/index/mapper/ParseContext.java
index 3c12f51a7f7..938dd778b0e 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/ParseContext.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/ParseContext.java
@@ -181,11 +181,6 @@ public abstract class ParseContext {
this.in = in;
}
- @Override
- public boolean flyweight() {
- return in.flyweight();
- }
-
@Override
public DocumentMapperParser docMapperParser() {
return in.docMapperParser();
@@ -411,11 +406,6 @@ public abstract class ParseContext {
this.dynamicMappingsUpdate = null;
}
- @Override
- public boolean flyweight() {
- return sourceToParse.flyweight();
- }
-
@Override
public DocumentMapperParser docMapperParser() {
return this.docMapperParser;
@@ -580,8 +570,6 @@ public abstract class ParseContext {
}
}
- public abstract boolean flyweight();
-
public abstract DocumentMapperParser docMapperParser();
/**
@@ -658,6 +646,7 @@ public abstract class ParseContext {
public abstract SourceToParse sourceToParse();
+ @Nullable
public abstract BytesReference source();
// only should be used by SourceFieldMapper to update with a compressed source
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java b/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java
index f65072d489e..6094caa319a 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java
@@ -46,8 +46,6 @@ public class SourceToParse {
private final XContentParser parser;
- private boolean flyweight = false;
-
private String index;
private String type;
@@ -106,15 +104,6 @@ public class SourceToParse {
return this;
}
- public SourceToParse flyweight(boolean flyweight) {
- this.flyweight = flyweight;
- return this;
- }
-
- public boolean flyweight() {
- return this.flyweight;
- }
-
public String id() {
return this.id;
}
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/internal/IdFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/internal/IdFieldMapper.java
index a586a7b5b94..1f26dd60841 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/internal/IdFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/internal/IdFieldMapper.java
@@ -220,7 +220,7 @@ public class IdFieldMapper extends MetadataFieldMapper {
@Override
public void postParse(ParseContext context) throws IOException {
- if (context.id() == null && !context.sourceToParse().flyweight()) {
+ if (context.id() == null) {
throw new MapperParsingException("No id found while parsing the content source");
}
// it either get built in the preParse phase, or get parsed...
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/internal/ParentFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/internal/ParentFieldMapper.java
index 86009ffcccc..e7cd1b107ae 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/internal/ParentFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/internal/ParentFieldMapper.java
@@ -228,9 +228,7 @@ public class ParentFieldMapper extends MetadataFieldMapper {
@Override
public void postParse(ParseContext context) throws IOException {
- if (context.sourceToParse().flyweight() == false) {
- parse(context);
- }
+ parse(context);
}
@Override
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java
index 1925b2b2faa..519a38c4ff3 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/internal/SourceFieldMapper.java
@@ -251,10 +251,11 @@ public class SourceFieldMapper extends MetadataFieldMapper {
if (!fieldType().stored()) {
return;
}
- if (context.flyweight()) {
+ BytesReference source = context.source();
+ // Percolate and tv APIs may not set the source and that is ok, because these APIs will not index any data
+ if (source == null) {
return;
}
- BytesReference source = context.source();
boolean filtered = (includes != null && includes.length > 0) || (excludes != null && excludes.length > 0);
if (filtered) {
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/internal/TTLFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/internal/TTLFieldMapper.java
index dbf63a7f801..7c51b05cb4b 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/internal/TTLFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/internal/TTLFieldMapper.java
@@ -212,7 +212,7 @@ public class TTLFieldMapper extends MetadataFieldMapper {
@Override
protected void parseCreateField(ParseContext context, List fields) throws IOException, AlreadyExpiredException {
- if (enabledState.enabled && !context.sourceToParse().flyweight()) {
+ if (enabledState.enabled) {
long ttl = context.sourceToParse().ttl();
if (ttl <= 0 && defaultTTL > 0) { // no ttl provided so we use the default value
ttl = defaultTTL;
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/internal/UidFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/internal/UidFieldMapper.java
index 828651409b1..f8fea4071e5 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/internal/UidFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/internal/UidFieldMapper.java
@@ -149,7 +149,7 @@ public class UidFieldMapper extends MetadataFieldMapper {
@Override
public void postParse(ParseContext context) throws IOException {
- if (context.id() == null && !context.sourceToParse().flyweight()) {
+ if (context.id() == null) {
throw new MapperParsingException("No id found while parsing the content source");
}
// if we did not have the id as part of the sourceToParse, then we need to parse it here
diff --git a/core/src/main/java/org/elasticsearch/index/percolator/PercolatorFieldMapper.java b/core/src/main/java/org/elasticsearch/index/percolator/PercolatorFieldMapper.java
index c4b2b06e0e0..9a103195746 100644
--- a/core/src/main/java/org/elasticsearch/index/percolator/PercolatorFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/percolator/PercolatorFieldMapper.java
@@ -126,9 +126,7 @@ public class PercolatorFieldMapper extends FieldMapper {
public Mapper parse(ParseContext context) throws IOException {
QueryShardContext queryShardContext = new QueryShardContext(this.queryShardContext);
Query query = PercolatorQueriesRegistry.parseQuery(queryShardContext, mapUnmappedFieldAsString, context.parser());
- if (context.flyweight() == false) {
- ExtractQueryTermsService.extractQueryTerms(query, context.doc(), queryTermsField.name(), unknownQueryField.name(), queryTermsField.fieldType());
- }
+ ExtractQueryTermsService.extractQueryTerms(query, context.doc(), queryTermsField.name(), unknownQueryField.name(), queryTermsField.fieldType());
return null;
}
diff --git a/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java b/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
index c78d125ab46..97416e17211 100644
--- a/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
+++ b/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
@@ -292,7 +292,7 @@ public class TermVectorsService {
private ParsedDocument parseDocument(IndexShard indexShard, String index, String type, BytesReference doc) throws Throwable {
MapperService mapperService = indexShard.mapperService();
DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(type);
- ParsedDocument parsedDocument = docMapper.getDocumentMapper().parse(source(doc).index(index).type(type).flyweight(true));
+ ParsedDocument parsedDocument = docMapper.getDocumentMapper().parse(source(doc).index(index).type(type).id("_id_for_tv_api"));
if (docMapper.getMapping() != null) {
parsedDocument.addDynamicMappingsUpdate(docMapper.getMapping());
}
diff --git a/core/src/main/java/org/elasticsearch/percolator/PercolateDocumentParser.java b/core/src/main/java/org/elasticsearch/percolator/PercolateDocumentParser.java
index 973aa18b8fc..946d30edcc4 100644
--- a/core/src/main/java/org/elasticsearch/percolator/PercolateDocumentParser.java
+++ b/core/src/main/java/org/elasticsearch/percolator/PercolateDocumentParser.java
@@ -24,6 +24,7 @@ import org.apache.lucene.search.Query;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.percolate.PercolateShardRequest;
import org.elasticsearch.cluster.action.index.MappingUpdatedAction;
+import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
@@ -34,6 +35,7 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.DocumentMapperForType;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParsedDocument;
+import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.aggregations.AggregationPhase;
@@ -93,7 +95,7 @@ public class PercolateDocumentParser {
DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(request.documentType());
String index = context.shardTarget().index();
- doc = docMapper.getDocumentMapper().parse(source(parser).index(index).type(request.documentType()).flyweight(true));
+ doc = docMapper.getDocumentMapper().parse(source(parser).index(index).type(request.documentType()).id("_id_for_percolate_api"));
if (docMapper.getMapping() != null) {
doc.addDynamicMappingsUpdate(docMapper.getMapping());
}
@@ -202,19 +204,15 @@ public class PercolateDocumentParser {
}
private ParsedDocument parseFetchedDoc(PercolateContext context, BytesReference fetchedDoc, MapperService mapperService, String index, String type) {
- try (XContentParser parser = XContentFactory.xContent(fetchedDoc).createParser(fetchedDoc)) {
- DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(type);
- ParsedDocument doc = docMapper.getDocumentMapper().parse(source(parser).index(index).type(type).flyweight(true));
- if (doc == null) {
- throw new ElasticsearchParseException("No doc to percolate in the request");
- }
- if (context.highlight() != null) {
- doc.setSource(fetchedDoc);
- }
- return doc;
- } catch (Throwable e) {
- throw new ElasticsearchParseException("failed to parse request", e);
+ DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(type);
+ ParsedDocument doc = docMapper.getDocumentMapper().parse(source(fetchedDoc).index(index).type(type).id("_id_for_percolate_api"));
+ if (doc == null) {
+ throw new ElasticsearchParseException("No doc to percolate in the request");
}
+ if (context.highlight() != null) {
+ doc.setSource(fetchedDoc);
+ }
+ return doc;
}
}
diff --git a/plugins/mapper-size/src/main/java/org/elasticsearch/index/mapper/size/SizeFieldMapper.java b/plugins/mapper-size/src/main/java/org/elasticsearch/index/mapper/size/SizeFieldMapper.java
index 6cd54eeaac0..984e83a438e 100644
--- a/plugins/mapper-size/src/main/java/org/elasticsearch/index/mapper/size/SizeFieldMapper.java
+++ b/plugins/mapper-size/src/main/java/org/elasticsearch/index/mapper/size/SizeFieldMapper.java
@@ -150,7 +150,7 @@ public class SizeFieldMapper extends MetadataFieldMapper {
if (!enabledState.enabled) {
return;
}
- if (context.flyweight()) {
+ if (context.source() == null) {
return;
}
fields.add(new IntegerFieldMapper.CustomIntegerNumericField(context.source().length(), fieldType()));
From aefdee17fd0d7caacc769f2df54beede12adb3f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christoph=20B=C3=BCscher?=
Date: Wed, 27 Jan 2016 18:56:19 +0100
Subject: [PATCH 11/11] Adding builder method to SmoothingModel implementations
Adds a method that emits a WordScorerFactory to all of the
three SmoothingModel implementatins that will be needed when
we switch to parsing the PhraseSuggestion on the coordinating
node and need to delay creating the WordScorer on the shards.
---
.../search/suggest/phrase/LaplaceScorer.java | 10 +-
.../phrase/LinearInterpoatingScorer.java | 14 ++-
.../phrase/PhraseSuggestionBuilder.java | 92 +++++++++++++------
.../suggest/phrase/StupidBackoffScorer.java | 4 +
.../suggest/phrase/LaplaceModelTests.java | 17 +++-
.../phrase/LinearInterpolationModelTests.java | 22 ++++-
...lTest.java => SmoothingModelTestCase.java} | 71 ++++++++++----
.../phrase/StupidBackoffModelTests.java | 17 +++-
8 files changed, 185 insertions(+), 62 deletions(-)
rename core/src/test/java/org/elasticsearch/search/suggest/phrase/{SmoothingModelTest.java => SmoothingModelTestCase.java} (68%)
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java
index 04d98c3827d..678f3082bac 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LaplaceScorer.java
@@ -27,14 +27,14 @@ import org.elasticsearch.search.suggest.phrase.DirectCandidateGenerator.Candidat
import java.io.IOException;
//TODO public for tests
public final class LaplaceScorer extends WordScorer {
-
+
public static final WordScorerFactory FACTORY = new WordScorer.WordScorerFactory() {
@Override
public WordScorer newScorer(IndexReader reader, Terms terms, String field, double realWordLikelyhood, BytesRef separator) throws IOException {
return new LaplaceScorer(reader, terms, field, realWordLikelyhood, separator, 0.5);
}
};
-
+
private double alpha;
public LaplaceScorer(IndexReader reader, Terms terms, String field,
@@ -42,7 +42,11 @@ public final class LaplaceScorer extends WordScorer {
super(reader, terms, field, realWordLikelyhood, separator);
this.alpha = alpha;
}
-
+
+ double alpha() {
+ return this.alpha;
+ }
+
@Override
protected double scoreBigram(Candidate word, Candidate w_1) throws IOException {
SuggestUtils.join(separator, spare, w_1.term, word.term);
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java
index d2b1ba48b13..368d461fc53 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/LinearInterpoatingScorer.java
@@ -41,7 +41,19 @@ public final class LinearInterpoatingScorer extends WordScorer {
this.bigramLambda = bigramLambda / sum;
this.trigramLambda = trigramLambda / sum;
}
-
+
+ double trigramLambda() {
+ return this.trigramLambda;
+ }
+
+ double bigramLambda() {
+ return this.bigramLambda;
+ }
+
+ double unigramLambda() {
+ return this.unigramLambda;
+ }
+
@Override
protected double scoreBigram(Candidate word, Candidate w_1) throws IOException {
SuggestUtils.join(separator, spare, w_1.term, word.term);
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java
index 97ca09d25a1..0e1fec6c7b2 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/PhraseSuggestionBuilder.java
@@ -18,8 +18,12 @@
*/
package org.elasticsearch.search.suggest.phrase;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Terms;
+import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParseFieldMatcher;
+import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.io.stream.NamedWriteable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
@@ -30,6 +34,7 @@ import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.Template;
import org.elasticsearch.search.suggest.SuggestBuilder.SuggestionBuilder;
+import org.elasticsearch.search.suggest.phrase.WordScorer.WordScorerFactory;
import java.io.IOException;
import java.util.ArrayList;
@@ -50,7 +55,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder> generators = new HashMap<>();
private Integer gramSize;
- private SmoothingModel> model;
+ private SmoothingModel model;
private Boolean forceUnigrams;
private Integer tokenLimit;
private String preTag;
@@ -159,7 +164,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder model) {
+ public PhraseSuggestionBuilder smoothingModel(SmoothingModel model) {
this.model = model;
return this;
}
@@ -292,7 +297,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder for details.
*
*/
- public static final class StupidBackoff extends SmoothingModel {
+ public static final class StupidBackoff extends SmoothingModel {
/**
* Default discount parameter for {@link StupidBackoff} smoothing
*/
@@ -341,8 +346,9 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder new StupidBackoffScorer(reader, terms, field, realWordLikelyhood, separator, discount);
+ }
}
/**
@@ -377,7 +389,7 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder for details.
*
*/
- public static final class Laplace extends SmoothingModel {
+ public static final class Laplace extends SmoothingModel {
private double alpha = DEFAULT_LAPLACE_ALPHA;
private static final String NAME = "laplace";
private static final ParseField ALPHA_FIELD = new ParseField("alpha");
@@ -419,13 +431,14 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder new LaplaceScorer(reader, terms, field, realWordLikelyhood, separator, alpha);
+ }
}
- public static abstract class SmoothingModel> implements NamedWriteable, ToXContent {
+ public static abstract class SmoothingModel implements NamedWriteable, ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
@@ -471,16 +490,18 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder for details.
*
*/
- public static final class LinearInterpolation extends SmoothingModel {
+ public static final class LinearInterpolation extends SmoothingModel {
private static final String NAME = "linear";
static final LinearInterpolation PROTOTYPE = new LinearInterpolation(0.8, 0.1, 0.1);
private final double trigramLambda;
@@ -563,10 +584,11 @@ public final class PhraseSuggestionBuilder extends SuggestionBuilder
+ new LinearInterpoatingScorer(reader, terms, field, realWordLikelyhood, separator, trigramLambda, bigramLambda,
+ unigramLambda);
}
}
diff --git a/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java b/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java
index fcf6064d228..5bd3d942b1a 100644
--- a/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java
+++ b/core/src/main/java/org/elasticsearch/search/suggest/phrase/StupidBackoffScorer.java
@@ -42,6 +42,10 @@ public class StupidBackoffScorer extends WordScorer {
this.discount = discount;
}
+ double discount() {
+ return this.discount;
+ }
+
@Override
protected double scoreBigram(Candidate word, Candidate w_1) throws IOException {
SuggestUtils.join(separator, spare, w_1.term, word.term);
diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java
index e2256e98f6a..87ad654e0cd 100644
--- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java
+++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LaplaceModelTests.java
@@ -20,11 +20,14 @@
package org.elasticsearch.search.suggest.phrase;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.Laplace;
+import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.SmoothingModel;
-public class LaplaceModelTests extends SmoothingModelTest {
+import static org.hamcrest.Matchers.instanceOf;
+
+public class LaplaceModelTests extends SmoothingModelTestCase {
@Override
- protected Laplace createTestModel() {
+ protected SmoothingModel createTestModel() {
return new Laplace(randomDoubleBetween(0.0, 10.0, false));
}
@@ -32,7 +35,15 @@ public class LaplaceModelTests extends SmoothingModelTest {
* mutate the given model so the returned smoothing model is different
*/
@Override
- protected Laplace createMutation(Laplace original) {
+ protected Laplace createMutation(SmoothingModel input) {
+ Laplace original = (Laplace) input;
return new Laplace(original.getAlpha() + 0.1);
}
+
+ @Override
+ void assertWordScorer(WordScorer wordScorer, SmoothingModel input) {
+ Laplace model = (Laplace) input;
+ assertThat(wordScorer, instanceOf(LaplaceScorer.class));
+ assertEquals(model.getAlpha(), ((LaplaceScorer) wordScorer).alpha(), Double.MIN_VALUE);
+ }
}
diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java
index 467bca7f0ab..1112b7a5ed7 100644
--- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java
+++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/LinearInterpolationModelTests.java
@@ -20,15 +20,18 @@
package org.elasticsearch.search.suggest.phrase;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.LinearInterpolation;
+import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.SmoothingModel;
-public class LinearInterpolationModelTests extends SmoothingModelTest {
+import static org.hamcrest.Matchers.instanceOf;
+
+public class LinearInterpolationModelTests extends SmoothingModelTestCase {
@Override
- protected LinearInterpolation createTestModel() {
+ protected SmoothingModel createTestModel() {
double trigramLambda = randomDoubleBetween(0.0, 10.0, false);
double bigramLambda = randomDoubleBetween(0.0, 10.0, false);
double unigramLambda = randomDoubleBetween(0.0, 10.0, false);
- // normalize
+ // normalize so parameters sum to 1
double sum = trigramLambda + bigramLambda + unigramLambda;
return new LinearInterpolation(trigramLambda / sum, bigramLambda / sum, unigramLambda / sum);
}
@@ -37,7 +40,8 @@ public class LinearInterpolationModelTests extends SmoothingModelTest> extends ESTestCase {
+public abstract class SmoothingModelTestCase extends ESTestCase {
private static NamedWriteableRegistry namedWriteableRegistry;
- private static IndicesQueriesRegistry indicesQueriesRegistry;
/**
* setup for the whole base test class
@@ -63,33 +76,31 @@ public abstract class SmoothingModelTest> extends E
namedWriteableRegistry.registerPrototype(SmoothingModel.class, LinearInterpolation.PROTOTYPE);
namedWriteableRegistry.registerPrototype(SmoothingModel.class, StupidBackoff.PROTOTYPE);
}
- indicesQueriesRegistry = new IndicesQueriesRegistry(Settings.settingsBuilder().build(), Collections.emptySet(), namedWriteableRegistry);
}
@AfterClass
public static void afterClass() throws Exception {
namedWriteableRegistry = null;
- indicesQueriesRegistry = null;
}
/**
* create random model that is put under test
*/
- protected abstract SM createTestModel();
+ protected abstract SmoothingModel createTestModel();
/**
* mutate the given model so the returned smoothing model is different
*/
- protected abstract SM createMutation(SM original) throws IOException;
+ protected abstract SmoothingModel createMutation(SmoothingModel original) throws IOException;
/**
* Test that creates new smoothing model from a random test smoothing model and checks both for equality
*/
public void testFromXContent() throws IOException {
- QueryParseContext context = new QueryParseContext(indicesQueriesRegistry);
+ QueryParseContext context = new QueryParseContext(new IndicesQueriesRegistry(Settings.settingsBuilder().build(), Collections.emptyMap()));
context.parseFieldMatcher(new ParseFieldMatcher(Settings.EMPTY));
- SM testModel = createTestModel();
+ SmoothingModel testModel = createTestModel();
XContentBuilder contentBuilder = XContentFactory.contentBuilder(randomFrom(XContentType.values()));
if (randomBoolean()) {
contentBuilder.prettyPrint();
@@ -99,21 +110,45 @@ public abstract class SmoothingModelTest> extends E
contentBuilder.endObject();
XContentParser parser = XContentHelper.createParser(contentBuilder.bytes());
context.reset(parser);
- SmoothingModel> prototype = (SmoothingModel>) namedWriteableRegistry.getPrototype(SmoothingModel.class,
+ parser.nextToken(); // go to start token, real parsing would do that in the outer element parser
+ SmoothingModel prototype = (SmoothingModel) namedWriteableRegistry.getPrototype(SmoothingModel.class,
testModel.getWriteableName());
- SmoothingModel> parsedModel = prototype.fromXContent(context);
+ SmoothingModel parsedModel = prototype.fromXContent(context);
assertNotSame(testModel, parsedModel);
assertEquals(testModel, parsedModel);
assertEquals(testModel.hashCode(), parsedModel.hashCode());
}
+ /**
+ * Test the WordScorer emitted by the smoothing model
+ */
+ public void testBuildWordScorer() throws IOException {
+ SmoothingModel testModel = createTestModel();
+
+ Map mapping = new HashMap<>();
+ mapping.put("field", new WhitespaceAnalyzer());
+ PerFieldAnalyzerWrapper wrapper = new PerFieldAnalyzerWrapper(new WhitespaceAnalyzer(), mapping);
+ IndexWriter writer = new IndexWriter(new RAMDirectory(), new IndexWriterConfig(wrapper));
+ Document doc = new Document();
+ doc.add(new Field("field", "someText", TextField.TYPE_NOT_STORED));
+ writer.addDocument(doc);
+ DirectoryReader ir = DirectoryReader.open(writer, false);
+
+ WordScorer wordScorer = testModel.buildWordScorerFactory().newScorer(ir, MultiFields.getTerms(ir , "field"), "field", 0.9d, BytesRefs.toBytesRef(" "));
+ assertWordScorer(wordScorer, testModel);
+ }
+
+ /**
+ * implementation dependant assertions on the wordScorer produced by the smoothing model under test
+ */
+ abstract void assertWordScorer(WordScorer wordScorer, SmoothingModel testModel);
+
/**
* Test serialization and deserialization of the tested model.
*/
- @SuppressWarnings("unchecked")
public void testSerialization() throws IOException {
- SM testModel = createTestModel();
- SM deserializedModel = (SM) copyModel(testModel);
+ SmoothingModel testModel = createTestModel();
+ SmoothingModel deserializedModel = copyModel(testModel);
assertEquals(testModel, deserializedModel);
assertEquals(testModel.hashCode(), deserializedModel.hashCode());
assertNotSame(testModel, deserializedModel);
@@ -124,7 +159,7 @@ public abstract class SmoothingModelTest> extends E
*/
@SuppressWarnings("unchecked")
public void testEqualsAndHashcode() throws IOException {
- SM firstModel = createTestModel();
+ SmoothingModel firstModel = createTestModel();
assertFalse("smoothing model is equal to null", firstModel.equals(null));
assertFalse("smoothing model is equal to incompatible type", firstModel.equals(""));
assertTrue("smoothing model is not equal to self", firstModel.equals(firstModel));
@@ -132,13 +167,13 @@ public abstract class SmoothingModelTest> extends E
equalTo(firstModel.hashCode()));
assertThat("different smoothing models should not be equal", createMutation(firstModel), not(equalTo(firstModel)));
- SM secondModel = (SM) copyModel(firstModel);
+ SmoothingModel secondModel = copyModel(firstModel);
assertTrue("smoothing model is not equal to self", secondModel.equals(secondModel));
assertTrue("smoothing model is not equal to its copy", firstModel.equals(secondModel));
assertTrue("equals is not symmetric", secondModel.equals(firstModel));
assertThat("smoothing model copy's hashcode is different from original hashcode", secondModel.hashCode(), equalTo(firstModel.hashCode()));
- SM thirdModel = (SM) copyModel(secondModel);
+ SmoothingModel thirdModel = copyModel(secondModel);
assertTrue("smoothing model is not equal to self", thirdModel.equals(thirdModel));
assertTrue("smoothing model is not equal to its copy", secondModel.equals(thirdModel));
assertThat("smoothing model copy's hashcode is different from original hashcode", secondModel.hashCode(), equalTo(thirdModel.hashCode()));
@@ -148,11 +183,11 @@ public abstract class SmoothingModelTest> extends E
assertTrue("equals is not symmetric", thirdModel.equals(firstModel));
}
- static SmoothingModel> copyModel(SmoothingModel> original) throws IOException {
+ static SmoothingModel copyModel(SmoothingModel original) throws IOException {
try (BytesStreamOutput output = new BytesStreamOutput()) {
original.writeTo(output);
try (StreamInput in = new NamedWriteableAwareStreamInput(StreamInput.wrap(output.bytes()), namedWriteableRegistry)) {
- SmoothingModel> prototype = (SmoothingModel>) namedWriteableRegistry.getPrototype(SmoothingModel.class, original.getWriteableName());
+ SmoothingModel prototype = (SmoothingModel) namedWriteableRegistry.getPrototype(SmoothingModel.class, original.getWriteableName());
return prototype.readFrom(in);
}
}
diff --git a/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java b/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java
index 5d774066e07..c3bd66d2a81 100644
--- a/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java
+++ b/core/src/test/java/org/elasticsearch/search/suggest/phrase/StupidBackoffModelTests.java
@@ -19,12 +19,15 @@
package org.elasticsearch.search.suggest.phrase;
+import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.SmoothingModel;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder.StupidBackoff;
-public class StupidBackoffModelTests extends SmoothingModelTest {
+import static org.hamcrest.Matchers.instanceOf;
+
+public class StupidBackoffModelTests extends SmoothingModelTestCase {
@Override
- protected StupidBackoff createTestModel() {
+ protected SmoothingModel createTestModel() {
return new StupidBackoff(randomDoubleBetween(0.0, 10.0, false));
}
@@ -32,7 +35,15 @@ public class StupidBackoffModelTests extends SmoothingModelTest {
* mutate the given model so the returned smoothing model is different
*/
@Override
- protected StupidBackoff createMutation(StupidBackoff original) {
+ protected StupidBackoff createMutation(SmoothingModel input) {
+ StupidBackoff original = (StupidBackoff) input;
return new StupidBackoff(original.getDiscount() + 0.1);
}
+
+ @Override
+ void assertWordScorer(WordScorer wordScorer, SmoothingModel input) {
+ assertThat(wordScorer, instanceOf(StupidBackoffScorer.class));
+ StupidBackoff testModel = (StupidBackoff) input;
+ assertEquals(testModel.getDiscount(), ((StupidBackoffScorer) wordScorer).discount(), Double.MIN_VALUE);
+ }
}