/* * 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.index.reindex; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.join.ParentJoinPlugin; import org.elasticsearch.plugins.Plugin; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import static org.elasticsearch.index.query.QueryBuilders.idsQuery; import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasToString; import static org.hamcrest.Matchers.instanceOf; /** * Index-by-search tests for parent/child. */ public class ReindexParentChildTests extends ReindexTestCase { QueryBuilder findsCountry; QueryBuilder findsCity; QueryBuilder findsNeighborhood; @Override protected boolean ignoreExternalCluster() { return true; } @Override protected Collection<Class<? extends Plugin>> nodePlugins() { final List<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins()); plugins.add(ParentJoinPlugin.class); return Collections.unmodifiableList(plugins); } @Override protected Collection<Class<? extends Plugin>> transportClientPlugins() { return nodePlugins(); } public void testParentChild() throws Exception { createParentChildIndex("source"); createParentChildIndex("dest"); createParentChildDocs("source"); // Copy parent to the new index ReindexRequestBuilder copy = reindex().source("source").destination("dest").filter(findsCountry).refresh(true); assertThat(copy.get(), matcher().created(1)); // Copy the child to a new index copy = reindex().source("source").destination("dest").filter(findsCity).refresh(true); assertThat(copy.get(), matcher().created(1)); // Make sure parent/child is intact on that index assertSearchHits(client().prepareSearch("dest").setQuery(findsCity).get(), "pittsburgh"); // Copy the grandchild to a new index copy = reindex().source("source").destination("dest").filter(findsNeighborhood).refresh(true); assertThat(copy.get(), matcher().created(1)); // Make sure parent/child is intact on that index assertSearchHits(client().prepareSearch("dest").setQuery(findsNeighborhood).get(), "make-believe"); // Copy the parent/child/grandchild structure all at once to a third index createParentChildIndex("dest_all_at_once"); copy = reindex().source("source").destination("dest_all_at_once").refresh(true); assertThat(copy.get(), matcher().created(3)); // Make sure parent/child/grandchild is intact there too assertSearchHits(client().prepareSearch("dest_all_at_once").setQuery(findsNeighborhood).get(), "make-believe"); } public void testErrorMessageWhenBadParentChild() throws Exception { createParentChildIndex("source"); createParentChildDocs("source"); ReindexRequestBuilder copy = reindex().source("source").destination("dest").filter(findsCity); final BulkByScrollResponse response = copy.get(); assertThat(response.getBulkFailures().size(), equalTo(1)); final Exception cause = response.getBulkFailures().get(0).getCause(); assertThat(cause, instanceOf(IllegalArgumentException.class)); assertThat(cause, hasToString(containsString("can't specify parent if no parent field has been configured"))); } /** * Setup a parent/child index and return a query that should find the child * using the parent. */ private void createParentChildIndex(String indexName) throws Exception { CreateIndexRequestBuilder create = client().admin().indices().prepareCreate(indexName); create.setSettings("index.mapping.single_type", false); create.addMapping("city", "{\"_parent\": {\"type\": \"country\"}}", XContentType.JSON); create.addMapping("neighborhood", "{\"_parent\": {\"type\": \"city\"}}", XContentType.JSON); assertAcked(create); ensureGreen(); } private void createParentChildDocs(String indexName) throws Exception { indexRandom(true, client().prepareIndex(indexName, "country", "united states").setSource("foo", "bar"), client().prepareIndex(indexName, "city", "pittsburgh").setParent("united states").setSource("foo", "bar"), client().prepareIndex(indexName, "neighborhood", "make-believe").setParent("pittsburgh") .setSource("foo", "bar").setRouting("united states")); findsCountry = idsQuery("country").addIds("united states"); findsCity = hasParentQuery("country", findsCountry, false); findsNeighborhood = hasParentQuery("city", findsCity, false); // Make sure we built the parent/child relationship assertSearchHits(client().prepareSearch(indexName).setQuery(findsCity).get(), "pittsburgh"); assertSearchHits(client().prepareSearch(indexName).setQuery(findsNeighborhood).get(), "make-believe"); } }