@Ignore("https://github.com/elasticsearch/elasticsearch/issues/9904")
  @Test
  public void testShapeFilterWithRandomGeoCollection() throws Exception {
    // Create a random geometry collection.
    GeometryCollectionBuilder gcb = RandomShapeGenerator.createGeometryCollection(getRandom());

    logger.info("Created Random GeometryCollection containing " + gcb.numShapes() + " shapes");

    createIndex("randshapes");
    assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape"));

    XContentBuilder docSource =
        gcb.toXContent(jsonBuilder().startObject().field("location"), null).endObject();
    indexRandom(true, client().prepareIndex("test", "type", "1").setSource(docSource));

    ensureSearchable("test");

    ShapeBuilder filterShape = (gcb.getShapeAt(randomIntBetween(0, gcb.numShapes() - 1)));

    GeoShapeFilterBuilder filter =
        FilterBuilders.geoShapeFilter("location", filterShape, ShapeRelation.INTERSECTS);
    SearchResponse result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
  }
  @Test
  public void testParsingMultipleShapes() throws Exception {
    String mapping =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("type1")
            .startObject("properties")
            .startObject("location1")
            .field("type", "geo_shape")
            .endObject()
            .startObject("location2")
            .field("type", "geo_shape")
            .endObject()
            .endObject()
            .endObject()
            .endObject()
            .string();

    assertAcked(prepareCreate("test").addMapping("type1", mapping));
    ensureYellow();

    String p1 =
        "\"location1\" : {\"type\":\"polygon\", \"coordinates\":[[[-10,-10],[10,-10],[10,10],[-10,10],[-10,-10]]]}";
    String p2 =
        "\"location2\" : {\"type\":\"polygon\", \"coordinates\":[[[-20,-20],[20,-20],[20,20],[-20,20],[-20,-20]]]}";
    String o1 = "{" + p1 + ", " + p2 + "}";

    indexRandom(true, client().prepareIndex("test", "type1", "1").setSource(o1));

    String filter =
        "{\"geo_shape\": {\"location2\": {\"indexed_shape\": {"
            + "\"id\": \"1\","
            + "\"type\": \"type1\","
            + "\"index\": \"test\","
            + "\"path\": \"location2\""
            + "}}}}";

    SearchResponse result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .execute()
            .actionGet();
    assertSearchResponse(result);
    assertHitCount(result, 1);
  }
  @Test
  public void testStringSortMissingAscTerminates() throws Exception {
    assertAcked(
        prepareCreate("test")
            .setSettings(
                Settings.settingsBuilder()
                    .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
                    .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0))
            .addMapping("test", "no_field", "type=string", "some_field", "type=string"));
    client().prepareIndex("test", "test", "1").setSource("some_field", "test").get();
    refresh();

    SearchResponse response =
        client()
            .prepareSearch("test")
            .setTypes("test")
            .addSort(new FieldSortBuilder("no_field").order(SortOrder.ASC).missing("_last"))
            .setScroll("1m")
            .get();
    assertHitCount(response, 1);
    assertSearchHits(response, "1");

    response = client().prepareSearchScroll(response.getScrollId()).get();
    assertSearchResponse(response);
    assertHitCount(response, 1);
    assertNoSearchHits(response);

    response =
        client()
            .prepareSearch("test")
            .setTypes("test")
            .addSort(new FieldSortBuilder("no_field").order(SortOrder.ASC).missing("_first"))
            .setScroll("1m")
            .get();
    assertHitCount(response, 1);
    assertSearchHits(response, "1");

    response = client().prepareSearchScroll(response.getScrollId()).get();
    assertHitCount(response, 1);
    assertThat(response.getHits().getHits().length, equalTo(0));
  }
  @Test
  public void testIndexPointsFilterRectangle() throws Exception {
    String mapping =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("type1")
            .startObject("properties")
            .startObject("location")
            .field("type", "geo_shape")
            .field("tree", "quadtree")
            .endObject()
            .endObject()
            .endObject()
            .endObject()
            .string();
    assertAcked(prepareCreate("test").addMapping("type1", mapping));
    ensureGreen();

    indexRandom(
        true,
        client()
            .prepareIndex("test", "type1", "1")
            .setSource(
                jsonBuilder()
                    .startObject()
                    .field("name", "Document 1")
                    .startObject("location")
                    .field("type", "point")
                    .startArray("coordinates")
                    .value(-30)
                    .value(-30)
                    .endArray()
                    .endObject()
                    .endObject()),
        client()
            .prepareIndex("test", "type1", "2")
            .setSource(
                jsonBuilder()
                    .startObject()
                    .field("name", "Document 2")
                    .startObject("location")
                    .field("type", "point")
                    .startArray("coordinates")
                    .value(-45)
                    .value(-50)
                    .endArray()
                    .endObject()
                    .endObject()));

    ShapeBuilder shape = ShapeBuilder.newEnvelope().topLeft(-45, 45).bottomRight(45, -45);

    SearchResponse searchResponse =
        client()
            .prepareSearch()
            .setQuery(filteredQuery(matchAllQuery(), geoIntersectionFilter("location", shape)))
            .execute()
            .actionGet();

    assertSearchResponse(searchResponse);
    assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l));
    assertThat(searchResponse.getHits().hits().length, equalTo(1));
    assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1"));

    searchResponse =
        client().prepareSearch().setQuery(geoShapeQuery("location", shape)).execute().actionGet();

    assertSearchResponse(searchResponse);
    assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l));
    assertThat(searchResponse.getHits().hits().length, equalTo(1));
    assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1"));
  }
  @Test
  public void testShapeFilterWithDefinedGeoCollection() throws Exception {
    createIndex("shapes");
    assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape"));

    XContentBuilder docSource =
        jsonBuilder()
            .startObject()
            .startObject("location")
            .field("type", "geometrycollection")
            .startArray("geometries")
            .startObject()
            .field("type", "point")
            .startArray("coordinates")
            .value(100.0)
            .value(0.0)
            .endArray()
            .endObject()
            .startObject()
            .field("type", "linestring")
            .startArray("coordinates")
            .startArray()
            .value(101.0)
            .value(0.0)
            .endArray()
            .startArray()
            .value(102.0)
            .value(1.0)
            .endArray()
            .endArray()
            .endObject()
            .endArray()
            .endObject()
            .endObject();
    indexRandom(true, client().prepareIndex("test", "type", "1").setSource(docSource));
    ensureSearchable("test");

    GeoShapeFilterBuilder filter =
        FilterBuilders.geoShapeFilter(
            "location",
            ShapeBuilder.newGeometryCollection()
                .polygon(
                    ShapeBuilder.newPolygon()
                        .point(99.0, -1.0)
                        .point(99.0, 3.0)
                        .point(103.0, 3.0)
                        .point(103.0, -1.0)
                        .point(99.0, -1.0)),
            ShapeRelation.INTERSECTS);
    SearchResponse result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    filter =
        FilterBuilders.geoShapeFilter(
            "location",
            ShapeBuilder.newGeometryCollection()
                .polygon(
                    ShapeBuilder.newPolygon()
                        .point(199.0, -11.0)
                        .point(199.0, 13.0)
                        .point(193.0, 13.0)
                        .point(193.0, -11.0)
                        .point(199.0, -11.0)),
            ShapeRelation.INTERSECTS);
    result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 0);
    filter =
        FilterBuilders.geoShapeFilter(
            "location",
            ShapeBuilder.newGeometryCollection()
                .polygon(
                    ShapeBuilder.newPolygon()
                        .point(99.0, -1.0)
                        .point(99.0, 3.0)
                        .point(103.0, 3.0)
                        .point(103.0, -1.0)
                        .point(99.0, -1.0))
                .polygon(
                    ShapeBuilder.newPolygon()
                        .point(199.0, -11.0)
                        .point(199.0, 13.0)
                        .point(193.0, 13.0)
                        .point(193.0, -11.0)
                        .point(199.0, -11.0)),
            ShapeRelation.INTERSECTS);
    result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
  }
  @Test
  public void testShapeFetchingPath() throws Exception {
    createIndex("shapes");
    assertAcked(prepareCreate("test").addMapping("type", "location", "type=geo_shape"));

    String location =
        "\"location\" : {\"type\":\"polygon\", \"coordinates\":[[[-10,-10],[10,-10],[10,10],[-10,10],[-10,-10]]]}";
    indexRandom(
        true,
        client()
            .prepareIndex("shapes", "type", "1")
            .setSource(
                String.format(
                    Locale.ROOT,
                    "{ %s, \"1\" : { %s, \"2\" : { %s, \"3\" : { %s } }} }",
                    location,
                    location,
                    location,
                    location)),
        client()
            .prepareIndex("test", "type", "1")
            .setSource(
                jsonBuilder()
                    .startObject()
                    .startObject("location")
                    .field("type", "polygon")
                    .startArray("coordinates")
                    .startArray()
                    .startArray()
                    .value(-20)
                    .value(-20)
                    .endArray()
                    .startArray()
                    .value(20)
                    .value(-20)
                    .endArray()
                    .startArray()
                    .value(20)
                    .value(20)
                    .endArray()
                    .startArray()
                    .value(-20)
                    .value(20)
                    .endArray()
                    .startArray()
                    .value(-20)
                    .value(-20)
                    .endArray()
                    .endArray()
                    .endArray()
                    .endObject()
                    .endObject()));
    ensureSearchable("test", "shapes");

    GeoShapeFilterBuilder filter =
        FilterBuilders.geoShapeFilter("location", "1", "type", ShapeRelation.INTERSECTS)
            .indexedShapeIndex("shapes")
            .indexedShapePath("location");
    SearchResponse result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    filter =
        FilterBuilders.geoShapeFilter("location", "1", "type", ShapeRelation.INTERSECTS)
            .indexedShapeIndex("shapes")
            .indexedShapePath("1.location");
    result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    filter =
        FilterBuilders.geoShapeFilter("location", "1", "type", ShapeRelation.INTERSECTS)
            .indexedShapeIndex("shapes")
            .indexedShapePath("1.2.location");
    result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    filter =
        FilterBuilders.geoShapeFilter("location", "1", "type", ShapeRelation.INTERSECTS)
            .indexedShapeIndex("shapes")
            .indexedShapePath("1.2.3.location");
    result =
        client()
            .prepareSearch("test")
            .setQuery(QueryBuilders.matchAllQuery())
            .setPostFilter(filter)
            .get();
    assertSearchResponse(result);
    assertHitCount(result, 1);

    // now test the query variant
    GeoShapeQueryBuilder query =
        QueryBuilders.geoShapeQuery("location", "1", "type")
            .indexedShapeIndex("shapes")
            .indexedShapePath("location");
    result = client().prepareSearch("test").setQuery(query).get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    query =
        QueryBuilders.geoShapeQuery("location", "1", "type")
            .indexedShapeIndex("shapes")
            .indexedShapePath("1.location");
    result = client().prepareSearch("test").setQuery(query).get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    query =
        QueryBuilders.geoShapeQuery("location", "1", "type")
            .indexedShapeIndex("shapes")
            .indexedShapePath("1.2.location");
    result = client().prepareSearch("test").setQuery(query).get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
    query =
        QueryBuilders.geoShapeQuery("location", "1", "type")
            .indexedShapeIndex("shapes")
            .indexedShapePath("1.2.3.location");
    result = client().prepareSearch("test").setQuery(query).get();
    assertSearchResponse(result);
    assertHitCount(result, 1);
  }
  @Test
  public void testEdgeCases() throws Exception {

    String mapping =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("type1")
            .startObject("properties")
            .startObject("location")
            .field("type", "geo_shape")
            .field("tree", "quadtree")
            .endObject()
            .endObject()
            .endObject()
            .endObject()
            .string();
    assertAcked(prepareCreate("test").addMapping("type1", mapping));
    ensureGreen();

    indexRandom(
        true,
        client()
            .prepareIndex("test", "type1", "blakely")
            .setSource(
                jsonBuilder()
                    .startObject()
                    .field("name", "Blakely Island")
                    .startObject("location")
                    .field("type", "polygon")
                    .startArray("coordinates")
                    .startArray()
                    .startArray()
                    .value(-122.83)
                    .value(48.57)
                    .endArray()
                    .startArray()
                    .value(-122.77)
                    .value(48.56)
                    .endArray()
                    .startArray()
                    .value(-122.79)
                    .value(48.53)
                    .endArray()
                    .startArray()
                    .value(-122.83)
                    .value(48.57)
                    .endArray() // close the polygon
                    .endArray()
                    .endArray()
                    .endObject()
                    .endObject()));

    ShapeBuilder query =
        ShapeBuilder.newEnvelope().topLeft(-122.88, 48.62).bottomRight(-122.82, 48.54);

    // This search would fail if both geoshape indexing and geoshape filtering
    // used the bottom-level optimization in SpatialPrefixTree#recursiveGetNodes.
    SearchResponse searchResponse =
        client()
            .prepareSearch()
            .setQuery(filteredQuery(matchAllQuery(), geoIntersectionFilter("location", query)))
            .execute()
            .actionGet();

    assertSearchResponse(searchResponse);
    assertThat(searchResponse.getHits().getTotalHits(), equalTo(1l));
    assertThat(searchResponse.getHits().hits().length, equalTo(1));
    assertThat(searchResponse.getHits().getAt(0).id(), equalTo("blakely"));
  }