diff --git a/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java b/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java index 60d3cfc71b6..bbe613b61c9 100644 --- a/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java +++ b/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java @@ -21,11 +21,14 @@ package org.elasticsearch.index.shard; import org.apache.lucene.search.Query; import org.apache.lucene.search.join.BitDocIdSetFilter; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.Version; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.lucene.search.Queries; +import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.aliases.IndexAliasesService; import org.elasticsearch.index.cache.IndexCache; import org.elasticsearch.index.engine.Engine; @@ -37,6 +40,8 @@ import org.elasticsearch.index.mapper.MapperUtils; import org.elasticsearch.index.mapper.Mapping; import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.query.IndexQueryParserService; +import org.elasticsearch.index.query.ParsedQuery; +import org.elasticsearch.index.query.QueryParsingException; import org.elasticsearch.index.translog.Translog; import java.util.HashMap; @@ -160,7 +165,24 @@ public class TranslogRecoveryPerformer { if (types == null) { types = Strings.EMPTY_ARRAY; } - Query query = queryParserService.parseQuery(source).query(); + Query query; + try { + query = queryParserService.parseQuery(source).query(); + } catch (QueryParsingException ex) { + // for BWC we try to parse directly the query since pre 1.0.0.Beta2 we didn't require a top level query field + if ( queryParserService.getIndexCreatedVersion().onOrBefore(Version.V_1_0_0_Beta2)) { + try { + XContentParser parser = XContentHelper.createParser(source); + ParsedQuery parse = queryParserService.parse(parser); + query = parse.query(); + } catch (Throwable t) { + ex.addSuppressed(t); + throw ex; + } + } else { + throw ex; + } + } Query searchFilter = mapperService.searchFilter(types); if (searchFilter != null) { query = Queries.filtered(query, searchFilter); diff --git a/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java b/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java index 97e988f819f..da7f17ce48d 100644 --- a/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java +++ b/src/test/java/org/elasticsearch/index/shard/IndexShardTests.java @@ -19,22 +19,26 @@ package org.elasticsearch.index.shard; import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.stats.IndexStats; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.routing.MutableShardRouting; import org.elasticsearch.cluster.routing.ShardRouting; import org.elasticsearch.cluster.routing.ShardRoutingState; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.NodeEnvironment; import org.elasticsearch.env.ShardLock; import org.elasticsearch.index.IndexService; import org.elasticsearch.index.engine.Engine; +import org.elasticsearch.index.query.QueryParsingException; import org.elasticsearch.index.translog.Translog; import org.elasticsearch.index.translog.TranslogConfig; import org.elasticsearch.indices.IndicesService; import org.elasticsearch.test.DummyShardLock; import org.elasticsearch.test.ElasticsearchSingleNodeTest; +import org.elasticsearch.test.VersionUtils; import org.junit.Test; import java.io.IOException; @@ -329,4 +333,33 @@ public class IndexShardTests extends ElasticsearchSingleNodeTest { client().admin().indices().prepareUpdateSettings(shard.shardId.getIndex()).setSettings(settingsBuilder().put(TranslogConfig.INDEX_TRANSLOG_DURABILITY, durabilty.name()).build()).get(); assertEquals(durabilty, shard.getTranslogDurability()); } + + public void testDeleteByQueryBWC() { + Version version = VersionUtils.randomVersion(random()); + assertAcked(client().admin().indices().prepareCreate("test") + .setSettings(SETTING_NUMBER_OF_SHARDS, 1, SETTING_NUMBER_OF_REPLICAS, 0, IndexMetaData.SETTING_VERSION_CREATED, version.id)); + ensureGreen("test"); + client().prepareIndex("test", "person").setSource("{ \"user\" : \"kimchy\" }").get(); + + IndicesService indicesService = getInstanceFromNode(IndicesService.class); + IndexService test = indicesService.indexService("test"); + IndexShard shard = test.shard(0); + int numDocs = 1; + shard.state = IndexShardState.RECOVERING; + try { + shard.recoveryState().getTranslog().totalOperations(1); + shard.engine().config().getTranslogRecoveryPerformer().performRecoveryOperation(shard.engine(), new Translog.DeleteByQuery(new Engine.DeleteByQuery(null, new BytesArray("{\"term\" : { \"user\" : \"kimchy\" }}"), null, null, null, Engine.Operation.Origin.RECOVERY, 0, "person"))); + assertTrue(version.onOrBefore(Version.V_1_0_0_Beta2)); + numDocs = 0; + } catch (QueryParsingException ex) { + assertTrue(version.after(Version.V_1_0_0_Beta2)); + } finally { + shard.state = IndexShardState.STARTED; + } + shard.engine().refresh("foo"); + + try (Engine.Searcher searcher = shard.engine().acquireSearcher("foo")) { + assertEquals(numDocs, searcher.reader().numDocs()); + } + } }