You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by mm...@apache.org on 2018/07/20 17:41:46 UTC

[33/53] [abbrv] calcite git commit: [CALCITE-2376] Unify ES2 and ES5 adapters. Migrate to low-level ES rest client as main transport. (Andrei Sereda)

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
new file mode 100644
index 0000000..456fbac
--- /dev/null
+++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticSearchAdapterTest.java
@@ -0,0 +1,400 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.adapter.elasticsearch;
+
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.schema.impl.ViewTable;
+import org.apache.calcite.schema.impl.ViewTableMacro;
+import org.apache.calcite.test.CalciteAssert;
+import org.apache.calcite.test.ElasticsearchChecker;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpStatus;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
+
+import com.google.common.io.LineProcessor;
+import com.google.common.io.Resources;
+
+import org.elasticsearch.client.Response;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Set of tests for ES adapter. Uses real instance via {@link EmbeddedElasticsearchPolicy}. Document
+ * source is local {@code zips-mini.json} file (located in test classpath).
+ */
+public class ElasticSearchAdapterTest {
+
+  @ClassRule //init once for all tests
+  public static final EmbeddedElasticsearchPolicy NODE = EmbeddedElasticsearchPolicy.create();
+
+  /** Default index/type name */
+  private static final String ZIPS = "zips";
+
+  /**
+   * Used to create {@code zips} index and insert zip data in bulk.
+   * @throws Exception when instance setup failed
+   */
+  @BeforeClass
+  public static void setupInstance() throws Exception {
+    // hardcoded mapping definition
+    final String mapping = String.format(Locale.ROOT,
+        "{'mappings':{'%s':{'properties':"
+            + "{'city':{'type':'keyword'},'state':{'type':'keyword'},'pop':{'type':'long'}}"
+            + "}}}", ZIPS).replace('\'', '"');
+
+    // create index and mapping
+    final HttpEntity entity = new StringEntity(mapping, ContentType.APPLICATION_JSON);
+    NODE.restClient().performRequest("PUT", "/" + ZIPS, Collections.emptyMap(), entity);
+
+    // load records from file
+    final List<String> bulk = new ArrayList<>();
+    Resources.readLines(ElasticSearchAdapterTest.class.getResource("/zips-mini.json"),
+        StandardCharsets.UTF_8, new LineProcessor<Void>() {
+          @Override public boolean processLine(String line) throws IOException {
+            bulk.add("{\"index\": {} }"); // index/type will be derived from _bulk URI
+            line = line.replaceAll("_id", "id"); // _id is a reserved attribute in ES
+            bulk.add(line);
+            return true;
+          }
+
+          @Override public Void getResult() {
+            return null;
+          }
+        });
+
+    if (bulk.isEmpty()) {
+      throw new IllegalStateException("No records to index. Empty file ?");
+    }
+
+    final String uri = String.format(Locale.ROOT, "/%s/%s/_bulk?refresh", ZIPS, ZIPS);
+    Response response = NODE.restClient().performRequest("POST", uri,
+        Collections.emptyMap(),
+        new StringEntity(String.join("\n", bulk) + "\n", ContentType.APPLICATION_JSON));
+
+    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+      final String error = EntityUtils.toString(response.getEntity());
+      final String message = String.format(Locale.ROOT,
+          "Couldn't bulk insert %d elements into %s (%s/%s). Error was %s\n%s\n",
+          bulk.size(), ZIPS, response.getHost(),
+          response.getRequestLine(),
+          response.getStatusLine(), error);
+
+      throw new IllegalStateException(message);
+    }
+
+  }
+
+  private CalciteAssert.ConnectionFactory newConnectionFactory() {
+    return new CalciteAssert.ConnectionFactory() {
+      @Override public Connection createConnection() throws SQLException {
+        final Connection connection = DriverManager.getConnection("jdbc:calcite:");
+        final SchemaPlus root = connection.unwrap(CalciteConnection.class).getRootSchema();
+
+        root.add("elastic", new ElasticsearchSchema(NODE.restClient(), NODE.mapper(), ZIPS));
+
+        // add calcite view programmatically
+        final String viewSql = "select cast(_MAP['city'] AS varchar(20)) AS \"city\", "
+            + " cast(_MAP['loc'][0] AS float) AS \"longitude\",\n"
+            + " cast(_MAP['loc'][1] AS float) AS \"latitude\",\n"
+            + " cast(_MAP['pop'] AS integer) AS \"pop\", "
+            +  " cast(_MAP['state'] AS varchar(2)) AS \"state\", "
+            +  " cast(_MAP['id'] AS varchar(5)) AS \"id\" "
+            +  "from \"elastic\".\"zips\"";
+
+        ViewTableMacro macro = ViewTable.viewMacro(root, viewSql,
+            Collections.singletonList("elastic"), Arrays.asList("elastic", "view"), false);
+        root.add("ZIPS", macro);
+
+        return connection;
+      }
+    };
+  }
+
+  private CalciteAssert.AssertThat calciteAssert() {
+    return CalciteAssert.that()
+        .with(newConnectionFactory());
+  }
+
+  /**
+   * Tests using calcite view
+   */
+  @Test
+  public void view() {
+    calciteAssert()
+        .query("select * from zips where \"city\" = 'BROOKLYN'")
+        .returns("city=BROOKLYN; longitude=-73.956985; latitude=40.646694; "
+            + "pop=111396; state=NY; id=11226\n")
+        .returnsCount(1);
+  }
+
+  @Test
+  public void emptyResult() {
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from zips limit 0")
+        .returnsCount(0);
+
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from \"elastic\".\"zips\" where _MAP['Foo'] = '_MISSING_'")
+        .returnsCount(0);
+  }
+
+  @Test
+  public void basic() throws Exception {
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from \"elastic\".\"zips\" where _MAP['city'] = 'BROOKLYN'")
+        .returnsCount(1);
+
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from \"elastic\".\"zips\" where"
+            + " _MAP['city'] in ('BROOKLYN', 'WASHINGTON')")
+        .returnsCount(2);
+
+    // lower-case
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from \"elastic\".\"zips\" where "
+            + "_MAP['city'] in ('brooklyn', 'Brooklyn', 'BROOK') ")
+        .returnsCount(0);
+
+    // missing field
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from \"elastic\".\"zips\" where _MAP['CITY'] = 'BROOKLYN'")
+        .returnsCount(0);
+
+    // limit works
+    CalciteAssert.that()
+        .with(newConnectionFactory())
+        .query("select * from \"elastic\".\"zips\" limit 42")
+        .returnsCount(42);
+
+  }
+
+  @Test public void testSort() {
+    final String explain = "PLAN=ElasticsearchToEnumerableConverter\n"
+        + "  ElasticsearchSort(sort0=[$4], dir0=[ASC])\n"
+        + "    ElasticsearchProject(city=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], longitude=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], latitude=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], pop=[CAST(ITEM($0, 'pop')):INTEGER], state=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], id=[CAST(ITEM($0, 'id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
+        + "      ElasticsearchTableScan(table=[[elastic, zips]])";
+
+    calciteAssert()
+        .query("select * from zips order by \"state\"")
+        .returnsCount(10)
+        .explainContains(explain);
+  }
+
+  @Test public void testSortLimit() {
+    final String sql = "select \"state\", \"pop\" from zips\n"
+        + "order by \"state\", \"pop\" offset 2 rows fetch next 3 rows only";
+    calciteAssert()
+        .query(sql)
+        .returnsUnordered("state=AK; pop=32383",
+            "state=AL; pop=42124",
+            "state=AL; pop=43862")
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker(
+                "\"_source\" : [\"state\", \"pop\"]",
+                "\"sort\": [ {\"state\": \"asc\"}, {\"pop\": \"asc\"}]",
+                "\"from\": 2",
+                "\"size\": 3"));
+  }
+
+
+
+  @Test public void testOffsetLimit() {
+    final String sql = "select \"state\", \"id\" from zips\n"
+        + "offset 2 fetch next 3 rows only";
+    calciteAssert()
+        .query(sql)
+        .runs()
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker(
+                "\"from\": 2",
+                "\"size\": 3",
+                "\"_source\" : [\"state\", \"id\"]"));
+  }
+
+  @Test public void testLimit() {
+    final String sql = "select \"state\", \"id\" from zips\n"
+        + "fetch next 3 rows only";
+
+    calciteAssert()
+        .query(sql)
+        .runs()
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker(
+                "\"size\": 3",
+                "\"_source\" : [\"state\", \"id\"]"));
+  }
+
+  @Test public void testFilterSort() {
+    final String sql = "select * from zips\n"
+        + "where \"state\" = 'CA' and \"pop\" >= 94000\n"
+        + "order by \"state\", \"pop\"";
+    final String explain = "PLAN=ElasticsearchToEnumerableConverter\n"
+        + "  ElasticsearchSort(sort0=[$4], sort1=[$3], dir0=[ASC], dir1=[ASC])\n"
+        + "    ElasticsearchProject(city=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], longitude=[CAST(ITEM(ITEM($0, 'loc'), 0)):FLOAT], latitude=[CAST(ITEM(ITEM($0, 'loc'), 1)):FLOAT], pop=[CAST(ITEM($0, 'pop')):INTEGER], state=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], id=[CAST(ITEM($0, 'id')):VARCHAR(5) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
+        + "      ElasticsearchFilter(condition=[AND(=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA'), >=(CAST(ITEM($0, 'pop')):INTEGER, 94000))])\n"
+        + "        ElasticsearchTableScan(table=[[elastic, zips]])\n\n";
+    calciteAssert()
+        .query(sql)
+        .returnsOrdered("city=NORWALK; longitude=-118.081767; latitude=33.90564;"
+                + " pop=94188; state=CA; id=90650",
+            "city=LOS ANGELES; longitude=-118.258189; latitude=34.007856;"
+                + " pop=96074; state=CA; id=90011",
+            "city=BELL GARDENS; longitude=-118.17205; latitude=33.969177;"
+                + " pop=99568; state=CA; id=90201")
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker("\"query\" : "
+                    + "{\"constant_score\":{\"filter\":{\"bool\":"
+                    + "{\"must\":[{\"term\":{\"state\":\"CA\"}},"
+                    + "{\"range\":{\"pop\":{\"gte\":94000}}}]}}}}",
+                "\"script_fields\": {\"longitude\":{\"script\":\"params._source.loc[0]\"}, "
+                    + "\"latitude\":{\"script\":\"params._source.loc[1]\"}, "
+                    + "\"city\":{\"script\": \"params._source.city\"}, "
+                    + "\"pop\":{\"script\": \"params._source.pop\"}, "
+                    + "\"state\":{\"script\": \"params._source.state\"}, "
+                    + "\"id\":{\"script\": \"params._source.id\"}}",
+                "\"sort\": [ {\"state\": \"asc\"}, {\"pop\": \"asc\"}]"))
+        .explainContains(explain);
+  }
+
+  @Test public void testFilterSortDesc() {
+    final String sql = "select * from zips\n"
+        + "where \"pop\" BETWEEN 95000 AND 100000\n"
+        + "order by \"state\" desc, \"pop\"";
+    calciteAssert()
+        .query(sql)
+        .limit(4)
+        .returnsOrdered(
+            "city=LOS ANGELES; longitude=-118.258189; latitude=34.007856; pop=96074; state=CA; id=90011",
+            "city=BELL GARDENS; longitude=-118.17205; latitude=33.969177; pop=99568; state=CA; id=90201");
+  }
+
+  @Test public void testFilterRedundant() {
+    final String sql = "select * from zips\n"
+        + "where \"state\" > 'CA' and \"state\" < 'AZ' and \"state\" = 'OK'";
+    calciteAssert()
+        .query(sql)
+        .runs()
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker(""
+                    + "\"query\" : {\"constant_score\":{\"filter\":{\"bool\":"
+                    + "{\"must\":[{\"term\":{\"state\":\"OK\"}}]}}}}",
+                "\"script_fields\": {\"longitude\":{\"script\":\"params._source.loc[0]\"}, "
+                    +  "\"latitude\":{\"script\":\"params._source.loc[1]\"}, "
+                    +   "\"city\":{\"script\": \"params._source.city\"}, "
+                    +   "\"pop\":{\"script\": \"params._source.pop\"}, \"state\":{\"script\": \"params._source.state\"}, "
+                    +            "\"id\":{\"script\": \"params._source.id\"}}"
+            ));
+  }
+
+  @Test public void testInPlan() {
+    final String[] searches = {
+        "\"query\" : {\"constant_score\":{\"filter\":{\"bool\":{\"should\":"
+            + "[{\"bool\":{\"must\":[{\"term\":{\"pop\":96074}}]}},{\"bool\":{\"must\":[{\"term\":"
+            + "{\"pop\":99568}}]}}]}}}}",
+        "\"script_fields\": {\"longitude\":{\"script\":\"params._source.loc[0]\"}, "
+            +  "\"latitude\":{\"script\":\"params._source.loc[1]\"}, "
+            +  "\"city\":{\"script\": \"params._source.city\"}, "
+            +  "\"pop\":{\"script\": \"params._source.pop\"}, "
+            +  "\"state\":{\"script\": \"params._source.state\"}, "
+            +  "\"id\":{\"script\": \"params._source.id\"}}"
+    };
+
+    calciteAssert()
+        .query("select * from zips where \"pop\" in (96074, 99568)")
+        .returnsUnordered(
+            "city=BELL GARDENS; longitude=-118.17205; latitude=33.969177; pop=99568; state=CA; id=90201",
+            "city=LOS ANGELES; longitude=-118.258189; latitude=34.007856; pop=96074; state=CA; id=90011"
+        )
+        .queryContains(ElasticsearchChecker.elasticsearchChecker(searches));
+  }
+
+  @Test public void testZips() {
+    calciteAssert()
+        .query("select \"state\", \"city\" from zips")
+        .returnsCount(10);
+  }
+
+  @Test public void testProject() {
+    final String sql = "select \"state\", \"city\", 0 as \"zero\"\n"
+        + "from zips\n"
+        + "order by \"state\", \"city\"";
+
+    calciteAssert()
+        .query(sql)
+        .limit(2)
+        .returnsUnordered("state=AK; city=ANCHORAGE; zero=0",
+            "state=AK; city=FAIRBANKS; zero=0")
+        .queryContains(
+            ElasticsearchChecker.elasticsearchChecker("\"script_fields\": "
+                    + "{\"zero\":{\"script\": \"0\"}, "
+                    + "\"state\":{\"script\": \"params._source.state\"}, "
+                    + "\"city\":{\"script\": \"params._source.city\"}}",
+                "\"sort\": [ {\"state\": \"asc\"}, {\"city\": \"asc\"}]"));
+  }
+
+  @Test public void testFilter() {
+    final String explain = "PLAN=ElasticsearchToEnumerableConverter\n"
+        + "  ElasticsearchProject(state=[CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"], city=[CAST(ITEM($0, 'city')):VARCHAR(20) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\"])\n"
+        + "    ElasticsearchFilter(condition=[=(CAST(ITEM($0, 'state')):VARCHAR(2) CHARACTER SET \"ISO-8859-1\" COLLATE \"ISO-8859-1$en_US$primary\", 'CA')])\n"
+        + "      ElasticsearchTableScan(table=[[elastic, zips]])";
+    calciteAssert()
+        .query("select \"state\", \"city\" from zips where \"state\" = 'CA'")
+        .limit(3)
+        .returnsUnordered("state=CA; city=BELL GARDENS",
+            "state=CA; city=LOS ANGELES",
+            "state=CA; city=NORWALK")
+        .explainContains(explain);
+  }
+
+  @Test public void testFilterReversed() {
+    calciteAssert()
+        .query("select \"state\", \"city\" from zips where 'WI' < \"state\" order by \"city\"")
+        .limit(2)
+        .returnsUnordered("state=WV; city=BECKLEY",
+            "state=WY; city=CHEYENNE");
+    calciteAssert()
+        .query("select \"state\", \"city\" from zips where \"state\" > 'WI' order by \"city\"")
+        .limit(2)
+        .returnsUnordered("state=WV; city=BECKLEY",
+            "state=WY; city=CHEYENNE");
+  }
+
+}
+
+// End ElasticSearchAdapterTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchVersionTest.java
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchVersionTest.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchVersionTest.java
new file mode 100644
index 0000000..b25d76b
--- /dev/null
+++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/ElasticsearchVersionTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.adapter.elasticsearch;
+
+import org.junit.Test;
+
+import java.util.Locale;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Basic tests for parsing ES version in different formats
+ */
+public class ElasticsearchVersionTest {
+
+  @Test
+  public void versions() {
+    assertEquals(ElasticsearchVersion.fromString("2.3.4"), ElasticsearchVersion.ES2);
+    assertEquals(ElasticsearchVersion.fromString("2.0.0"), ElasticsearchVersion.ES2);
+    assertEquals(ElasticsearchVersion.fromString("5.6.1"), ElasticsearchVersion.ES5);
+    assertEquals(ElasticsearchVersion.fromString("6.0.1"), ElasticsearchVersion.ES6);
+    assertEquals(ElasticsearchVersion.fromString("7.0.1"), ElasticsearchVersion.ES7);
+    assertEquals(ElasticsearchVersion.fromString("111.0.1"), ElasticsearchVersion.UNKNOWN);
+
+    assertFails("");
+    assertFails(".");
+    assertFails(".1.2");
+    assertFails("1.2");
+    assertFails("0");
+    assertFails("b");
+    assertFails("a.b");
+    assertFails("aa");
+    assertFails("a.b.c");
+    assertFails("2.2");
+    assertFails("a.2");
+    assertFails("2.2.0a");
+    assertFails("2a.2.0");
+  }
+
+  private static void assertFails(String version) {
+    try {
+      ElasticsearchVersion.fromString(version);
+      fail(String.format(Locale.ROOT, "Should fail for version %s", version));
+    } catch (IllegalArgumentException ignore) {
+      // expected
+    }
+  }
+}
+
+// End ElasticsearchVersionTest.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchNode.java
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchNode.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchNode.java
new file mode 100644
index 0000000..5dfb1f6
--- /dev/null
+++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchNode.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.adapter.elasticsearch;
+
+import com.google.common.base.Preconditions;
+import com.google.common.io.Files;
+
+import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
+import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.transport.TransportAddress;
+import org.elasticsearch.node.InternalSettingsPreparer;
+import org.elasticsearch.node.Node;
+import org.elasticsearch.node.NodeValidationException;
+import org.elasticsearch.painless.PainlessPlugin;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.transport.Netty4Plugin;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Objects;
+
+/**
+ * Represents a single elastic search node which can run embedded in a java application.
+ * Intended for unit and integration tests. Settings and plugins are crafted for Calcite.
+ */
+class EmbeddedElasticsearchNode implements AutoCloseable {
+
+  private final Node node;
+  private volatile boolean  isStarted;
+
+  private EmbeddedElasticsearchNode(Node node) {
+    this.node = Objects.requireNonNull(node, "node");
+  }
+
+
+  /**
+   * Creates an instance with existing settings
+   * @param settings configuration parameters of ES instance
+   * @return instance which needs to be explicitly started (using {@link #start()})
+   */
+  private static EmbeddedElasticsearchNode create(Settings settings) {
+    // ensure GroovyPlugin is installed or otherwise scripted fields would not work
+    Node node = new LocalNode(settings, Arrays.asList(Netty4Plugin.class, PainlessPlugin.class));
+    return new EmbeddedElasticsearchNode(node);
+  }
+
+  /**
+   * Creates elastic node as single member of a cluster. Node will not be started
+   * unless {@link #start()} is explicitly called.
+   * @return instance which needs to be explicitly started (using {@link #start()})
+   */
+  public static EmbeddedElasticsearchNode create() {
+    File data = Files.createTempDir();
+    data.deleteOnExit();
+    File home = Files.createTempDir();
+    home.deleteOnExit();
+
+    Settings settings = Settings.builder()
+        .put("node.name", "fake-elastic")
+        .put("path.home", home.getAbsolutePath())
+        .put("path.data", data.getAbsolutePath())
+        .put("http.type", "netty4")
+        .put("network.host", "localhost")
+        .build();
+
+    return create(settings);
+  }
+
+  /**
+   * Starts current node
+   */
+  public void start() {
+    Preconditions.checkState(!isStarted, "already started");
+    try {
+      node.start();
+      this.isStarted = true;
+    } catch (NodeValidationException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Returns current address to connect to with HTTP client.
+   * @return hostname/port for HTTP connection
+   */
+  public TransportAddress httpAddress() {
+    Preconditions.checkState(isStarted, "node is not started");
+
+    NodesInfoResponse response =  client().admin().cluster().prepareNodesInfo()
+        .execute().actionGet();
+    if (response.getNodes().size() != 1) {
+      throw new IllegalStateException("Expected single node but got "
+          + response.getNodes().size());
+    }
+    NodeInfo node = response.getNodes().get(0);
+    return node.getHttp().address().boundAddresses()[0];
+  }
+
+  /**
+   * Exposes elastic
+   * <a href="https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/transport-client.html">transport client</a>
+   *
+   * (use of HTTP client is preferred).
+   * @return current elastic search client
+   */
+  public Client client() {
+    Preconditions.checkState(isStarted, "node is not started");
+    return node.client();
+  }
+
+  @Override public void close() throws Exception {
+    node.close();
+    // cleanup data dirs
+    for (String name: Arrays.asList("path.data", "path.home")) {
+      if (node.settings().get(name) != null) {
+        File file = new File(node.settings().get(name));
+        if (file.exists()) {
+          file.delete();
+        }
+      }
+    }
+  }
+
+  /**
+   * Having separate class to expose (protected) constructor which allows to install
+   * different plugins. In our case it is {@code GroovyPlugin} for scripted fields
+   * like {@code loc[0]} or {@code loc[1]['foo']}.
+   *
+   * <p>This class is intended solely for tests
+   */
+  private static class LocalNode extends Node {
+
+    private LocalNode(Settings settings, Collection<Class<? extends Plugin>> classpathPlugins) {
+      super(InternalSettingsPreparer.prepareEnvironment(settings, null),
+          classpathPlugins);
+    }
+  }
+}
+
+// End EmbeddedElasticsearchNode.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java
new file mode 100644
index 0000000..1ef9175
--- /dev/null
+++ b/elasticsearch/src/test/java/org/apache/calcite/adapter/elasticsearch/EmbeddedElasticsearchPolicy.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.adapter.elasticsearch;
+
+import org.apache.calcite.util.Closer;
+
+import org.apache.http.HttpHost;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.elasticsearch.client.RestClient;
+import org.elasticsearch.common.transport.TransportAddress;
+import org.junit.rules.ExternalResource;
+
+import java.util.Objects;
+
+/**
+ * Used to initialize a single elastic node. For performance reasons (node startup costs),
+ * same instance is usually shared across multiple tests.
+ *
+ * This rule should be used as follows:
+ * <pre>
+ *  public class MyTest {
+ *    &#64;ClassRule
+ *    public static final EmbeddedElasticsearchPolicy RULE = EmbeddedElasticsearchPolicy.create();
+ *
+ *    &#64;BeforeClass
+ *    public static void setup() {
+ *       // ... populate instance
+ *    }
+ *
+ *    &#64;Test
+ *    public void myTest() {
+ *      TransportAddress address = RULE.httpAddress();
+ *      // ....
+ *    }
+ *  }
+ *  </pre>
+ * @see ExternalResource
+ */
+class EmbeddedElasticsearchPolicy extends ExternalResource {
+
+  private final EmbeddedElasticsearchNode node;
+  private final ObjectMapper mapper;
+  private final Closer closer;
+  private RestClient client;
+
+  private EmbeddedElasticsearchPolicy(EmbeddedElasticsearchNode resource) {
+    this.node = Objects.requireNonNull(resource, "resource");
+    this.mapper = new ObjectMapper();
+    this.closer = new Closer();
+    closer.add(node);
+  }
+
+  @Override protected void before() throws Throwable {
+    node.start();
+  }
+
+  @Override protected void after() {
+    closer.close();
+  }
+
+  /**
+   * Factory method to create this rule.
+   * @return managed resource to be used in unit tests
+   */
+  public static EmbeddedElasticsearchPolicy create() {
+    return new EmbeddedElasticsearchPolicy(EmbeddedElasticsearchNode.create());
+  }
+
+  /**
+   * Exposes Jackson API to be used for low-level ES.
+   * @return existing instance of ObjectMapper
+   */
+  ObjectMapper mapper() {
+    return mapper;
+  }
+
+  /**
+   * Low-level http rest client to elastic search
+   * @return current ES rest client
+   */
+  RestClient restClient() {
+    if (client != null) {
+      return client;
+    }
+    TransportAddress address = httpAddress();
+    RestClient client = RestClient.builder(new HttpHost(address.getAddress(), address.getPort()))
+            .build();
+    closer.add(client);
+    this.client = client;
+    return client;
+  }
+
+  /**
+   * HTTP address for rest clients (can be ES native or any other).
+   * @return http address to connect to
+   */
+  TransportAddress httpAddress() {
+    return node.httpAddress();
+  }
+
+}
+
+// End EmbeddedElasticsearchPolicy.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java b/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java
new file mode 100644
index 0000000..68fc073
--- /dev/null
+++ b/elasticsearch/src/test/java/org/apache/calcite/test/ElasticsearchChecker.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.test;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Internal util methods for ElasticSearch tests
+ */
+public class ElasticsearchChecker {
+
+  private ElasticsearchChecker() {}
+
+  /** Returns a function that checks that a particular Elasticsearch pipeline is
+   * generated to implement a query.
+   * @param strings expected expressions
+   * @return validation function
+   */
+  public static Consumer<List> elasticsearchChecker(final String... strings) {
+    return actual -> {
+      Object[] actualArray = actual == null || actual.isEmpty() ? null
+          : ((List) actual.get(0)).toArray();
+      CalciteAssert.assertArrayEqual("expected Elasticsearch query not found", strings,
+          actualArray);
+    };
+  }
+}
+
+// End ElasticsearchChecker.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/resources/log4j2.xml
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/resources/log4j2.xml b/elasticsearch/src/test/resources/log4j2.xml
new file mode 100644
index 0000000..c8d70aa
--- /dev/null
+++ b/elasticsearch/src/test/resources/log4j2.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ /*
+  ~  * Licensed to the Apache Software Foundation (ASF) under one or more
+  ~  * contributor license agreements.  See the NOTICE file distributed with
+  ~  * this work for additional information regarding copyright ownership.
+  ~  * The ASF licenses this file to you under the Apache License, Version 2.0
+  ~  * (the "License"); you may not use this file except in compliance with
+  ~  * the License.  You may obtain a copy of the License at
+  ~  *
+  ~  * http://www.apache.org/licenses/LICENSE-2.0
+  ~  *
+  ~  * Unless required by applicable law or agreed to in writing, software
+  ~  * distributed under the License is distributed on an "AS IS" BASIS,
+  ~  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  * See the License for the specific language governing permissions and
+  ~  * limitations under the License.
+  ~  */
+  ~
+  -->
+
+<Configuration status="WARN">
+
+  <Appenders>
+    <Console name="console" target="SYSTEM_OUT">
+      <PatternLayout
+          pattern="[%-5level] %d{HH:mm:ss.SSS} %logger{36}.%M() - %msg%n" />
+    </Console>
+  </Appenders>
+
+  <Loggers>
+    <Root level="INFO" additivity="false">
+      <AppenderRef ref="console" />
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch/src/test/resources/zips-mini.json
----------------------------------------------------------------------
diff --git a/elasticsearch/src/test/resources/zips-mini.json b/elasticsearch/src/test/resources/zips-mini.json
new file mode 100644
index 0000000..858117a
--- /dev/null
+++ b/elasticsearch/src/test/resources/zips-mini.json
@@ -0,0 +1,149 @@
+{ "_id" : "01701", "city" : "FRAMINGHAM", "loc" : [ -71.42548600000001, 42.300665 ], "pop" : 65046, "state" : "MA" }
+{ "_id" : "02154", "city" : "NORTH WALTHAM", "loc" : [ -71.236497, 42.382492 ], "pop" : 57871, "state" : "MA" }
+{ "_id" : "02401", "city" : "BROCKTON", "loc" : [ -71.03434799999999, 42.081571 ], "pop" : 59498, "state" : "MA" }
+{ "_id" : "02840", "city" : "MIDDLETOWN", "loc" : [ -71.30347999999999, 41.504502 ], "pop" : 47687, "state" : "RI" }
+{ "_id" : "02860", "city" : "PAWTUCKET", "loc" : [ -71.39071300000001, 41.872873 ], "pop" : 45442, "state" : "RI" }
+{ "_id" : "02895", "city" : "NORTH SMITHFIELD", "loc" : [ -71.513683, 41.99948 ], "pop" : 53733, "state" : "RI" }
+{ "_id" : "03060", "city" : "NASHUA", "loc" : [ -71.466684, 42.756395 ], "pop" : 41438, "state" : "NH" }
+{ "_id" : "03103", "city" : "MANCHESTER", "loc" : [ -71.449325, 42.965563 ], "pop" : 36613, "state" : "NH" }
+{ "_id" : "03301", "city" : "CONCORD", "loc" : [ -71.527734, 43.218525 ], "pop" : 34035, "state" : "NH" }
+{ "_id" : "04240", "city" : "LEWISTON", "loc" : [ -70.191619, 44.098538 ], "pop" : 40173, "state" : "ME" }
+{ "_id" : "04401", "city" : "BANGOR", "loc" : [ -68.791839, 44.824199 ], "pop" : 40434, "state" : "ME" }
+{ "_id" : "05301", "city" : "BRATTLEBORO", "loc" : [ -72.593322, 42.857353 ], "pop" : 17522, "state" : "VT" }
+{ "_id" : "05401", "city" : "BURLINGTON", "loc" : [ -73.219875, 44.484023 ], "pop" : 39127, "state" : "VT" }
+{ "_id" : "05701", "city" : "RUTLAND", "loc" : [ -72.97077299999999, 43.614131 ], "pop" : 22576, "state" : "VT" }
+{ "_id" : "06010", "city" : "BRISTOL", "loc" : [ -72.930193, 41.682293 ], "pop" : 60670, "state" : "CT" }
+{ "_id" : "06450", "city" : "MERIDEN", "loc" : [ -72.799734, 41.533396 ], "pop" : 59441, "state" : "CT" }
+{ "_id" : "06902", "city" : "STAMFORD", "loc" : [ -73.53742800000001, 41.052552 ], "pop" : 54605, "state" : "CT" }
+{ "_id" : "07002", "city" : "BAYONNE", "loc" : [ -74.119169, 40.666399 ], "pop" : 61444, "state" : "NJ" }
+{ "_id" : "07087", "city" : "WEEHAWKEN", "loc" : [ -74.030558, 40.768153 ], "pop" : 69646, "state" : "NJ" }
+{ "_id" : "07111", "city" : "IRVINGTON", "loc" : [ -74.23127100000001, 40.7261 ], "pop" : 60986, "state" : "NJ" }
+{ "_id" : "10021", "city" : "NEW YORK", "loc" : [ -73.958805, 40.768476 ], "pop" : 106564, "state" : "NY" }
+{ "_id" : "11226", "city" : "BROOKLYN", "loc" : [ -73.956985, 40.646694 ], "pop" : 111396, "state" : "NY" }
+{ "_id" : "11373", "city" : "JACKSON HEIGHTS", "loc" : [ -73.878551, 40.740388 ], "pop" : 88241, "state" : "NY" }
+{ "_id" : "17042", "city" : "CLEONA", "loc" : [ -76.425895, 40.335912 ], "pop" : 61993, "state" : "PA" }
+{ "_id" : "18042", "city" : "FORKS TOWNSHIP", "loc" : [ -75.23582, 40.6867 ], "pop" : 65784, "state" : "PA" }
+{ "_id" : "19143", "city" : "PHILADELPHIA", "loc" : [ -75.228819, 39.944815 ], "pop" : 80454, "state" : "PA" }
+{ "_id" : "19711", "city" : "NEWARK", "loc" : [ -75.737534, 39.701129 ], "pop" : 50573, "state" : "DE" }
+{ "_id" : "19720", "city" : "MANOR", "loc" : [ -75.589938, 39.67703 ], "pop" : 46906, "state" : "DE" }
+{ "_id" : "19901", "city" : "DOVER", "loc" : [ -75.535983, 39.156639 ], "pop" : 46005, "state" : "DE" }
+{ "_id" : "20011", "city" : "WASHINGTON", "loc" : [ -77.020251, 38.951786 ], "pop" : 62924, "state" : "DC" }
+{ "_id" : "20301", "city" : "PENTAGON", "loc" : [ -77.038196, 38.891019 ], "pop" : 21, "state" : "DC" }
+{ "_id" : "21061", "city" : "GLEN BURNIE", "loc" : [ -76.61886199999999, 39.158968 ], "pop" : 75692, "state" : "MD" }
+{ "_id" : "21207", "city" : "GWYNN OAK", "loc" : [ -76.734064, 39.329628 ], "pop" : 76002, "state" : "MD" }
+{ "_id" : "21215", "city" : "BALTIMORE", "loc" : [ -76.67939699999999, 39.344572 ], "pop" : 74402, "state" : "MD" }
+{ "_id" : "22901", "city" : "CHARLOTTESVILLE", "loc" : [ -78.490869, 38.054752 ], "pop" : 62708, "state" : "VA" }
+{ "_id" : "23464", "city" : "VIRGINIA BEACH", "loc" : [ -76.175909, 36.797772 ], "pop" : 67276, "state" : "VA" }
+{ "_id" : "23602", "city" : "NEWPORT NEWS", "loc" : [ -76.53212499999999, 37.131684 ], "pop" : 68525, "state" : "VA" }
+{ "_id" : "25801", "city" : "BECKLEY", "loc" : [ -81.206084, 37.793214 ], "pop" : 45196, "state" : "WV" }
+{ "_id" : "26003", "city" : "ELM GROVE", "loc" : [ -80.685126, 40.072736 ], "pop" : 49136, "state" : "WV" }
+{ "_id" : "26505", "city" : "STAR CITY", "loc" : [ -79.95422499999999, 39.633858 ], "pop" : 70185, "state" : "WV" }
+{ "_id" : "27292", "city" : "LEXINGTON", "loc" : [ -80.262049, 35.82306 ], "pop" : 69179, "state" : "NC" }
+{ "_id" : "28677", "city" : "STATESVILLE", "loc" : [ -80.894009, 35.799022 ], "pop" : 52895, "state" : "NC" }
+{ "_id" : "29150", "city" : "OSWEGO", "loc" : [ -80.32100800000001, 33.928199 ], "pop" : 46394, "state" : "SC" }
+{ "_id" : "29501", "city" : "FLORENCE", "loc" : [ -79.772786, 34.18375 ], "pop" : 66990, "state" : "SC" }
+{ "_id" : "29801", "city" : "AIKEN", "loc" : [ -81.71942900000001, 33.553024 ], "pop" : 51233, "state" : "SC" }
+{ "_id" : "30032", "city" : "DECATUR", "loc" : [ -84.263165, 33.740825 ], "pop" : 56056, "state" : "GA" }
+{ "_id" : "30906", "city" : "PEACH ORCHARD", "loc" : [ -82.038358, 33.402024 ], "pop" : 58646, "state" : "GA" }
+{ "_id" : "32216", "city" : "JACKSONVILLE", "loc" : [ -81.547387, 30.293907 ], "pop" : 58867, "state" : "FL" }
+{ "_id" : "33012", "city" : "HIALEAH", "loc" : [ -80.30589999999999, 25.865395 ], "pop" : 73194, "state" : "FL" }
+{ "_id" : "33311", "city" : "FORT LAUDERDALE", "loc" : [ -80.172786, 26.142104 ], "pop" : 65378, "state" : "FL" }
+{ "_id" : "35215", "city" : "CENTER POINT", "loc" : [ -86.693197, 33.635447 ], "pop" : 43862, "state" : "AL" }
+{ "_id" : "35401", "city" : "TUSCALOOSA", "loc" : [ -87.56266599999999, 33.196891 ], "pop" : 42124, "state" : "AL" }
+{ "_id" : "35901", "city" : "SOUTHSIDE", "loc" : [ -86.010279, 33.997248 ], "pop" : 44165, "state" : "AL" }
+{ "_id" : "37042", "city" : "CLARKSVILLE", "loc" : [ -87.418621, 36.585315 ], "pop" : 43296, "state" : "TN" }
+{ "_id" : "37211", "city" : "NASHVILLE", "loc" : [ -86.72403799999999, 36.072486 ], "pop" : 51478, "state" : "TN" }
+{ "_id" : "38109", "city" : "MEMPHIS", "loc" : [ -90.073238, 35.042538 ], "pop" : 60508, "state" : "TN" }
+{ "_id" : "39180", "city" : "VICKSBURG", "loc" : [ -90.85065, 32.325824 ], "pop" : 46968, "state" : "MS" }
+{ "_id" : "39401", "city" : "HATTIESBURG", "loc" : [ -89.306471, 31.314553 ], "pop" : 41866, "state" : "MS" }
+{ "_id" : "39440", "city" : "LAUREL", "loc" : [ -89.13115500000001, 31.705444 ], "pop" : 45040, "state" : "MS" }
+{ "_id" : "40214", "city" : "LOUISVILLE", "loc" : [ -85.77802699999999, 38.159318 ], "pop" : 42198, "state" : "KY" }
+{ "_id" : "40216", "city" : "SHIVELY", "loc" : [ -85.831771, 38.186138 ], "pop" : 41719, "state" : "KY" }
+{ "_id" : "40601", "city" : "HATTON", "loc" : [ -84.88061, 38.192831 ], "pop" : 46563, "state" : "KY" }
+{ "_id" : "44035", "city" : "ELYRIA", "loc" : [ -82.10508799999999, 41.372353 ], "pop" : 66674, "state" : "OH" }
+{ "_id" : "44060", "city" : "MENTOR", "loc" : [ -81.342133, 41.689468 ], "pop" : 60109, "state" : "OH" }
+{ "_id" : "44107", "city" : "EDGEWATER", "loc" : [ -81.79714300000001, 41.482654 ], "pop" : 59702, "state" : "OH" }
+{ "_id" : "46360", "city" : "MICHIGAN CITY", "loc" : [ -86.869899, 41.698031 ], "pop" : 55392, "state" : "IN" }
+{ "_id" : "47130", "city" : "JEFFERSONVILLE", "loc" : [ -85.735885, 38.307767 ], "pop" : 56543, "state" : "IN" }
+{ "_id" : "47906", "city" : "WEST LAFAYETTE", "loc" : [ -86.923661, 40.444025 ], "pop" : 54702, "state" : "IN" }
+{ "_id" : "48180", "city" : "TAYLOR", "loc" : [ -83.267269, 42.231738 ], "pop" : 70811, "state" : "MI" }
+{ "_id" : "48185", "city" : "WESTLAND", "loc" : [ -83.374908, 42.318882 ], "pop" : 84712, "state" : "MI" }
+{ "_id" : "48227", "city" : "DETROIT", "loc" : [ -83.193732, 42.388303 ], "pop" : 68390, "state" : "MI" }
+{ "_id" : "50010", "city" : "AMES", "loc" : [ -93.639398, 42.029859 ], "pop" : 52105, "state" : "IA" }
+{ "_id" : "50317", "city" : "PLEASANT HILL", "loc" : [ -93.549446, 41.612499 ], "pop" : 39883, "state" : "IA" }
+{ "_id" : "52001", "city" : "DUBUQUE", "loc" : [ -90.68191400000001, 42.514977 ], "pop" : 41934, "state" : "IA" }
+{ "_id" : "53209", "city" : "MILWAUKEE", "loc" : [ -87.947834, 43.118765 ], "pop" : 51008, "state" : "WI" }
+{ "_id" : "54401", "city" : "WAUSAU", "loc" : [ -89.633955, 44.963433 ], "pop" : 51083, "state" : "WI" }
+{ "_id" : "54901", "city" : "OSHKOSH", "loc" : [ -88.54363499999999, 44.021962 ], "pop" : 57187, "state" : "WI" }
+{ "_id" : "55106", "city" : "SAINT PAUL", "loc" : [ -93.048817, 44.968384 ], "pop" : 47905, "state" : "MN" }
+{ "_id" : "55112", "city" : "NEW BRIGHTON", "loc" : [ -93.199691, 45.074129 ], "pop" : 44128, "state" : "MN" }
+{ "_id" : "55337", "city" : "BURNSVILLE", "loc" : [ -93.275283, 44.76086 ], "pop" : 51421, "state" : "MN" }
+{ "_id" : "57103", "city" : "SIOUX FALLS", "loc" : [ -96.686415, 43.537386 ], "pop" : 32508, "state" : "SD" }
+{ "_id" : "57401", "city" : "ABERDEEN", "loc" : [ -98.485642, 45.466109 ], "pop" : 28786, "state" : "SD" }
+{ "_id" : "57701", "city" : "ROCKERVILLE", "loc" : [ -103.200259, 44.077041 ], "pop" : 45328, "state" : "SD" }
+{ "_id" : "58103", "city" : "FARGO", "loc" : [ -96.812252, 46.856406 ], "pop" : 38483, "state" : "ND" }
+{ "_id" : "58501", "city" : "BISMARCK", "loc" : [ -100.774755, 46.823448 ], "pop" : 36602, "state" : "ND" }
+{ "_id" : "58701", "city" : "MINOT", "loc" : [ -101.298476, 48.22914 ], "pop" : 42195, "state" : "ND" }
+{ "_id" : "59102", "city" : "BILLINGS", "loc" : [ -108.572662, 45.781265 ], "pop" : 40121, "state" : "MT" }
+{ "_id" : "59601", "city" : "HELENA", "loc" : [ -112.021283, 46.613066 ], "pop" : 40102, "state" : "MT" }
+{ "_id" : "59801", "city" : "MISSOULA", "loc" : [ -114.025207, 46.856274 ], "pop" : 33811, "state" : "MT" }
+{ "_id" : "60623", "city" : "CHICAGO", "loc" : [ -87.7157, 41.849015 ], "pop" : 112047, "state" : "IL" }
+{ "_id" : "60634", "city" : "NORRIDGE", "loc" : [ -87.796054, 41.945213 ], "pop" : 69160, "state" : "IL" }
+{ "_id" : "60650", "city" : "CICERO", "loc" : [ -87.76008, 41.84776 ], "pop" : 67670, "state" : "IL" }
+{ "_id" : "63031", "city" : "FLORISSANT", "loc" : [ -90.340097, 38.806865 ], "pop" : 52659, "state" : "MO" }
+{ "_id" : "63116", "city" : "SAINT LOUIS", "loc" : [ -90.26254299999999, 38.581356 ], "pop" : 49014, "state" : "MO" }
+{ "_id" : "63136", "city" : "JENNINGS", "loc" : [ -90.260189, 38.738878 ], "pop" : 54994, "state" : "MO" }
+{ "_id" : "66502", "city" : "MANHATTAN", "loc" : [ -96.585776, 39.193757 ], "pop" : 50178, "state" : "KS" }
+{ "_id" : "67212", "city" : "WICHITA", "loc" : [ -97.438344, 37.700683 ], "pop" : 41349, "state" : "KS" }
+{ "_id" : "67401", "city" : "BAVARIA", "loc" : [ -97.60878700000001, 38.823802 ], "pop" : 45208, "state" : "KS" }
+{ "_id" : "68104", "city" : "OMAHA", "loc" : [ -95.999888, 41.29186 ], "pop" : 35325, "state" : "NE" }
+{ "_id" : "68502", "city" : "LINCOLN", "loc" : [ -96.693763, 40.789282 ], "pop" : 27576, "state" : "NE" }
+{ "_id" : "68847", "city" : "KEARNEY", "loc" : [ -99.077883, 40.713608 ], "pop" : 28674, "state" : "NE" }
+{ "_id" : "70072", "city" : "MARRERO", "loc" : [ -90.110462, 29.859756 ], "pop" : 58905, "state" : "LA" }
+{ "_id" : "70117", "city" : "NEW ORLEANS", "loc" : [ -90.03124, 29.970298 ], "pop" : 56494, "state" : "LA" }
+{ "_id" : "70560", "city" : "NEW IBERIA", "loc" : [ -91.819959, 30.001027 ], "pop" : 56105, "state" : "LA" }
+{ "_id" : "72032", "city" : "CONWAY", "loc" : [ -92.423574, 35.084199 ], "pop" : 43236, "state" : "AR" }
+{ "_id" : "72076", "city" : "GRAVEL RIDGE", "loc" : [ -92.13043500000001, 34.881985 ], "pop" : 37428, "state" : "AR" }
+{ "_id" : "72401", "city" : "JONESBORO", "loc" : [ -90.69652600000001, 35.833016 ], "pop" : 53532, "state" : "AR" }
+{ "_id" : "73034", "city" : "EDMOND", "loc" : [ -97.47983499999999, 35.666483 ], "pop" : 43814, "state" : "OK" }
+{ "_id" : "73505", "city" : "LAWTON", "loc" : [ -98.455234, 34.617939 ], "pop" : 45542, "state" : "OK" }
+{ "_id" : "74801", "city" : "SHAWNEE", "loc" : [ -96.931321, 35.34907 ], "pop" : 40076, "state" : "OK" }
+{ "_id" : "78207", "city" : "SAN ANTONIO", "loc" : [ -98.52596699999999, 29.422855 ], "pop" : 58355, "state" : "TX" }
+{ "_id" : "78521", "city" : "BROWNSVILLE", "loc" : [ -97.461236, 25.922103 ], "pop" : 79463, "state" : "TX" }
+{ "_id" : "78572", "city" : "ALTON", "loc" : [ -98.342647, 26.24153 ], "pop" : 67604, "state" : "TX" }
+{ "_id" : "80123", "city" : "BOW MAR", "loc" : [ -105.07766, 39.596854 ], "pop" : 59418, "state" : "CO" }
+{ "_id" : "80221", "city" : "FEDERAL HEIGHTS", "loc" : [ -105.007985, 39.840562 ], "pop" : 54069, "state" : "CO" }
+{ "_id" : "80631", "city" : "GARDEN CITY", "loc" : [ -104.704756, 40.413968 ], "pop" : 53905, "state" : "CO" }
+{ "_id" : "82001", "city" : "CHEYENNE", "loc" : [ -104.796234, 41.143719 ], "pop" : 33107, "state" : "WY" }
+{ "_id" : "82070", "city" : "LARAMIE", "loc" : [ -105.581146, 41.312907 ], "pop" : 29327, "state" : "WY" }
+{ "_id" : "82716", "city" : "GILLETTE", "loc" : [ -105.497442, 44.282009 ], "pop" : 25968, "state" : "WY" }
+{ "_id" : "83301", "city" : "TWIN FALLS", "loc" : [ -114.469265, 42.556495 ], "pop" : 34539, "state" : "ID" }
+{ "_id" : "83704", "city" : "BOISE", "loc" : [ -116.295099, 43.633001 ], "pop" : 40912, "state" : "ID" }
+{ "_id" : "83814", "city" : "COEUR D ALENE", "loc" : [ -116.784976, 47.692841 ], "pop" : 33589, "state" : "ID" }
+{ "_id" : "84118", "city" : "KEARNS", "loc" : [ -111.98521, 40.652759 ], "pop" : 55999, "state" : "UT" }
+{ "_id" : "84120", "city" : "WEST VALLEY CITY", "loc" : [ -112.009783, 40.68708 ], "pop" : 52854, "state" : "UT" }
+{ "_id" : "84604", "city" : "PROVO", "loc" : [ -111.654906, 40.260681 ], "pop" : 43841, "state" : "UT" }
+{ "_id" : "85023", "city" : "PHOENIX", "loc" : [ -112.111838, 33.632383 ], "pop" : 54668, "state" : "AZ" }
+{ "_id" : "85204", "city" : "MESA", "loc" : [ -111.789554, 33.399168 ], "pop" : 55180, "state" : "AZ" }
+{ "_id" : "85364", "city" : "YUMA", "loc" : [ -114.642362, 32.701507 ], "pop" : 57131, "state" : "AZ" }
+{ "_id" : "87501", "city" : "POJOAQUE VALLEY", "loc" : [ -105.974818, 35.702472 ], "pop" : 51715, "state" : "NM" }
+{ "_id" : "88001", "city" : "LAS CRUCES", "loc" : [ -106.746034, 32.321641 ], "pop" : 57502, "state" : "NM" }
+{ "_id" : "88201", "city" : "ROSWELL", "loc" : [ -104.525857, 33.388504 ], "pop" : 53644, "state" : "NM" }
+{ "_id" : "89031", "city" : "NORTH LAS VEGAS", "loc" : [ -115.124832, 36.206228 ], "pop" : 48113, "state" : "NV" }
+{ "_id" : "89115", "city" : "LAS VEGAS", "loc" : [ -115.067062, 36.215818 ], "pop" : 51532, "state" : "NV" }
+{ "_id" : "89502", "city" : "RENO", "loc" : [ -119.776395, 39.497239 ], "pop" : 38332, "state" : "NV" }
+{ "_id" : "90011", "city" : "LOS ANGELES", "loc" : [ -118.258189, 34.007856 ], "pop" : 96074, "state" : "CA" }
+{ "_id" : "90201", "city" : "BELL GARDENS", "loc" : [ -118.17205, 33.969177 ], "pop" : 99568, "state" : "CA" }
+{ "_id" : "90650", "city" : "NORWALK", "loc" : [ -118.081767, 33.90564 ], "pop" : 94188, "state" : "CA" }
+{ "_id" : "96734", "city" : "KAILUA", "loc" : [ -157.744781, 21.406262 ], "pop" : 53403, "state" : "HI" }
+{ "_id" : "96744", "city" : "KANEOHE", "loc" : [ -157.811543, 21.422819 ], "pop" : 55236, "state" : "HI" }
+{ "_id" : "96818", "city" : "HONOLULU", "loc" : [ -157.926925, 21.353173 ], "pop" : 62915, "state" : "HI" }
+{ "_id" : "97005", "city" : "BEAVERTON", "loc" : [ -122.805395, 45.475035 ], "pop" : 46660, "state" : "OR" }
+{ "_id" : "97206", "city" : "PORTLAND", "loc" : [ -122.59727, 45.483995 ], "pop" : 43134, "state" : "OR" }
+{ "_id" : "97301", "city" : "SALEM", "loc" : [ -122.979692, 44.926039 ], "pop" : 48007, "state" : "OR" }
+{ "_id" : "98031", "city" : "KENT", "loc" : [ -122.193184, 47.388004 ], "pop" : 50515, "state" : "WA" }
+{ "_id" : "98059", "city" : "RENTON", "loc" : [ -122.151178, 47.467383 ], "pop" : 48197, "state" : "WA" }
+{ "_id" : "98310", "city" : "BREMERTON", "loc" : [ -122.629913, 47.601916 ], "pop" : 49057, "state" : "WA" }
+{ "_id" : "99504", "city" : "ANCHORAGE", "loc" : [ -149.74467, 61.203696 ], "pop" : 32383, "state" : "AK" }
+{ "_id" : "99709", "city" : "FAIRBANKS", "loc" : [ -147.846917, 64.85437 ], "pop" : 23238, "state" : "AK" }
+{ "_id" : "99801", "city" : "JUNEAU", "loc" : [ -134.529429, 58.362767 ], "pop" : 24947, "state" : "AK" }

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch2/pom.xml
----------------------------------------------------------------------
diff --git a/elasticsearch2/pom.xml b/elasticsearch2/pom.xml
deleted file mode 100644
index a017f7a..0000000
--- a/elasticsearch2/pom.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-Licensed to the Apache Software Foundation (ASF) under one or more
-contributor license agreements.  See the NOTICE file distributed with
-this work for additional information regarding copyright ownership.
-The ASF licenses this file to you under the Apache License, Version 2.0
-(the "License"); you may not use this file except in compliance with
-the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <groupId>org.apache.calcite</groupId>
-    <artifactId>calcite</artifactId>
-    <version>1.17.0-SNAPSHOT</version>
-  </parent>
-
-  <artifactId>calcite-elasticsearch2</artifactId>
-  <packaging>jar</packaging>
-  <version>1.17.0-SNAPSHOT</version>
-  <name>Calcite Elasticsearch</name>
-  <description>Elasticsearch adapter for Calcite</description>
-
-  <properties>
-    <top.dir>${project.basedir}/..</top.dir>
-  </properties>
-
-  <dependencies>
-    <dependency>
-      <groupId>com.google.guava</groupId>
-      <artifactId>guava</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.calcite</groupId>
-      <artifactId>calcite-core</artifactId>
-      <type>jar</type>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.calcite</groupId>
-      <artifactId>calcite-core</artifactId>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.calcite</groupId>
-      <artifactId>calcite-linq4j</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.elasticsearch</groupId>
-      <artifactId>elasticsearch</artifactId>
-      <version>${elasticsearch-java-driver.version}</version>
-    </dependency>
-    <dependency>
-      <!-- Lang groovy dependency is needed for testing with embedded ES (scripted fields like loc[0]) -->
-      <groupId>org.elasticsearch.module</groupId>
-      <artifactId>lang-groovy</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>com.carrotsearch</groupId>
-      <artifactId>hppc</artifactId>
-      <version>${hppc.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.slf4j</groupId>
-      <artifactId>slf4j-api</artifactId>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <artifactId>maven-dependency-plugin</artifactId>
-        <version>${maven-dependency-plugin.version}</version>
-        <executions>
-          <execution>
-            <id>analyze</id>
-            <goals>
-              <goal>analyze-only</goal>
-            </goals>
-            <configuration>
-              <failOnWarning>true</failOnWarning>
-              <!-- ignore "unused but declared" warnings -->
-              <ignoredUnusedDeclaredDependencies>
-                <ignoredUnusedDeclaredDependency>org.apache.calcite.avatica:avatica</ignoredUnusedDeclaredDependency>
-                <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-api</ignoredUnusedDeclaredDependency>
-                <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-log4j12</ignoredUnusedDeclaredDependency>
-              </ignoredUnusedDeclaredDependencies>
-            </configuration>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <executions>
-          <execution>
-            <goals>
-              <goal>test-jar</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-release-plugin</artifactId>
-      </plugin>
-      <!-- Parent module has the same plugin and does the work of
-          generating -sources.jar for each project. But without the
-          plugin declared here, IDEs don't know the sources are
-          available. -->
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-source-plugin</artifactId>
-        <executions>
-          <execution>
-            <id>attach-sources</id>
-            <phase>verify</phase>
-            <goals>
-              <goal>jar-no-fork</goal>
-              <goal>test-jar-no-fork</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-</project>

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Enumerator.java
----------------------------------------------------------------------
diff --git a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Enumerator.java b/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Enumerator.java
deleted file mode 100644
index 54e4357..0000000
--- a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Enumerator.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.adapter.elasticsearch2;
-
-import org.apache.calcite.avatica.util.DateTimeUtils;
-import org.apache.calcite.linq4j.Enumerator;
-import org.apache.calcite.linq4j.function.Function1;
-import org.apache.calcite.linq4j.tree.Primitive;
-
-import org.elasticsearch.search.SearchHit;
-
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Enumerator that reads from an Elasticsearch type.
- */
-public class Elasticsearch2Enumerator implements Enumerator<Object> {
-  private final Iterator<SearchHit> cursor;
-  private final Function1<SearchHit, Object> getter;
-  private Object current;
-
-  /**
-   * Creates an ElasticsearchEnumerator.
-   *
-   * @param cursor Iterator over Elasticsearch {@link SearchHit} objects
-   * @param getter Converts an object into a list of fields
-   */
-  public Elasticsearch2Enumerator(Iterator<SearchHit> cursor,
-      Function1<SearchHit, Object> getter) {
-    this.cursor = cursor;
-    this.getter = getter;
-  }
-
-  public Object current() {
-    return current;
-  }
-
-  public boolean moveNext() {
-    if (cursor.hasNext()) {
-      SearchHit map = cursor.next();
-      current = getter.apply(map);
-      return true;
-    } else {
-      current = null;
-      return false;
-    }
-  }
-
-  public void reset() {
-    throw new UnsupportedOperationException();
-  }
-
-  public void close() {
-    // nothing to do
-  }
-
-  private static Function1<SearchHit, Map> mapGetter() {
-    return searchHitFields -> (Map) searchHitFields.fields();
-  }
-
-  private static Function1<SearchHit, Object> singletonGetter(final String fieldName,
-      final Class fieldClass) {
-    return searchHitFields -> {
-      if (searchHitFields.fields().isEmpty()) {
-        return convert(searchHitFields.getSource(), fieldClass);
-      } else {
-        return convert(searchHitFields.getFields(), fieldClass);
-      }
-    };
-  }
-
-  /**
-   * Function that extracts a given set of fields from {@link SearchHit}
-   * objects.
-   *
-   * @param fields List of fields to project
-   *
-   * @return function that converts the search result into a generic array
-   */
-  private static Function1<SearchHit, Object[]> listGetter(
-      final List<Map.Entry<String, Class>> fields) {
-    return hit -> {
-      Object[] objects = new Object[fields.size()];
-      for (int i = 0; i < fields.size(); i++) {
-        final Map.Entry<String, Class> field = fields.get(i);
-        final String name = field.getKey();
-        if (hit.fields().isEmpty()) {
-          objects[i] = convert(hit.getSource().get(name), field.getValue());
-        } else if (hit.fields().containsKey(name)) {
-          objects[i] = convert(hit.field(name).getValue(), field.getValue());
-        } else {
-          throw new IllegalStateException(
-              String.format(Locale.ROOT, "No result for %s", field));
-        }
-      }
-      return objects;
-    };
-  }
-
-  static Function1<SearchHit, Object> getter(List<Map.Entry<String, Class>> fields) {
-    //noinspection unchecked
-    return fields == null
-      ? (Function1) mapGetter()
-      : fields.size() == 1
-      ? singletonGetter(fields.get(0).getKey(), fields.get(0).getValue())
-      : (Function1) listGetter(fields);
-  }
-
-  private static Object convert(Object o, Class clazz) {
-    if (o == null) {
-      return null;
-    }
-    Primitive primitive = Primitive.of(clazz);
-    if (primitive != null) {
-      clazz = primitive.boxClass;
-    } else {
-      primitive = Primitive.ofBox(clazz);
-    }
-    if (clazz.isInstance(o)) {
-      return o;
-    }
-    if (o instanceof Date && primitive != null) {
-      o = ((Date) o).getTime() / DateTimeUtils.MILLIS_PER_DAY;
-    }
-    if (o instanceof Number && primitive != null) {
-      return primitive.number((Number) o);
-    }
-    return o;
-  }
-}
-
-// End Elasticsearch2Enumerator.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Schema.java
----------------------------------------------------------------------
diff --git a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Schema.java b/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Schema.java
deleted file mode 100644
index 6d464c8..0000000
--- a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Schema.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.adapter.elasticsearch2;
-
-import org.apache.calcite.adapter.elasticsearch.ElasticsearchSchema;
-import org.apache.calcite.schema.Table;
-import org.apache.calcite.schema.impl.AbstractSchema;
-
-import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-
-import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
-import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
-import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
-import org.elasticsearch.client.Client;
-import org.elasticsearch.client.transport.TransportClient;
-import org.elasticsearch.cluster.metadata.MappingMetaData;
-import org.elasticsearch.cluster.node.DiscoveryNode;
-import org.elasticsearch.common.collect.ImmutableOpenMap;
-import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.common.transport.InetSocketTransportAddress;
-import org.elasticsearch.common.transport.TransportAddress;
-
-import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Schema mapped onto an index of ELASTICSEARCH types.
- *
- * <p>Each table in the schema is an ELASTICSEARCH type in that index.
- */
-public class Elasticsearch2Schema extends AbstractSchema
-    implements ElasticsearchSchema {
-  final String index;
-
-  private transient Client client;
-
-  /**
-   * Creates an Elasticsearch2 schema.
-   *
-   * @param coordinates Map of Elasticsearch node locations (host, port)
-   * @param userConfig Map of user-specified configurations
-   * @param indexName Elasticsearch database name, e.g. "usa".
-   */
-  Elasticsearch2Schema(Map<String, Integer> coordinates,
-      Map<String, String> userConfig, String indexName) {
-    super();
-
-    final List<InetSocketAddress> transportAddresses = new ArrayList<>();
-    for (Map.Entry<String, Integer> coordinate: coordinates.entrySet()) {
-      transportAddresses.add(
-          new InetSocketAddress(coordinate.getKey(), coordinate.getValue()));
-    }
-
-    open(transportAddresses, userConfig);
-
-    if (client != null) {
-      final String[] indices = client.admin().indices()
-          .getIndex(new GetIndexRequest().indices(indexName))
-          .actionGet().getIndices();
-      if (indices.length == 1) {
-        index = indices[0];
-      } else {
-        index = null;
-      }
-    } else {
-      index = null;
-    }
-  }
-
-  /**
-   * Allows schema to be instantiated from existing elastic search client.
-   * This constructor is used in tests.
-   *
-   * @param client Existing (injectable) client instance
-   * @param index Index name
-   */
-  @VisibleForTesting
-  Elasticsearch2Schema(Client client, String index) {
-    this.client = Objects.requireNonNull(client, "client");
-    this.index = Objects.requireNonNull(index, "index");
-  }
-
-  @Override protected Map<String, Table> getTableMap() {
-    final ImmutableMap.Builder<String, Table> builder = ImmutableMap.builder();
-
-    try {
-      GetMappingsResponse response = client.admin().indices()
-          .getMappings(new GetMappingsRequest().indices(index))
-          .get();
-      ImmutableOpenMap<String, MappingMetaData> mapping = response.getMappings().get(index);
-      for (ObjectObjectCursor<String, MappingMetaData> c: mapping) {
-        builder.put(c.key, new Elasticsearch2Table(client, index, c.key));
-      }
-    } catch (RuntimeException e) {
-      throw e;
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-    return builder.build();
-  }
-
-  private void open(List<InetSocketAddress> transportAddresses, Map<String, String> userConfig) {
-    final List<TransportAddress> transportNodes = new ArrayList<>(transportAddresses.size());
-    for (InetSocketAddress address : transportAddresses) {
-      transportNodes.add(new InetSocketTransportAddress(address));
-    }
-
-    Settings settings = Settings.settingsBuilder().put(userConfig).build();
-
-    final TransportClient transportClient = TransportClient.builder().settings(settings).build();
-    for (TransportAddress transport : transportNodes) {
-      transportClient.addTransportAddress(transport);
-    }
-
-    final List<DiscoveryNode> nodes = ImmutableList.copyOf(transportClient.connectedNodes());
-    if (nodes.isEmpty()) {
-      throw new IllegalStateException("Cannot connect to any elasticsearch node: "
-              + transportNodes);
-    }
-
-    client = transportClient;
-  }
-
-  @Override public String getIndex() {
-    return index;
-  }
-}
-
-// End Elasticsearch2Schema.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2SchemaFactory.java
----------------------------------------------------------------------
diff --git a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2SchemaFactory.java b/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2SchemaFactory.java
deleted file mode 100644
index 19378a0..0000000
--- a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2SchemaFactory.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.adapter.elasticsearch2;
-
-import org.apache.calcite.schema.Schema;
-import org.apache.calcite.schema.SchemaFactory;
-import org.apache.calcite.schema.SchemaPlus;
-
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Factory that creates an {@link Elasticsearch2Schema}.
- *
- * <p>Allows a custom schema to be included in a model.json file.
- */
-@SuppressWarnings("UnusedDeclaration")
-public class Elasticsearch2SchemaFactory implements SchemaFactory {
-
-  public Elasticsearch2SchemaFactory() {
-  }
-
-  @Override public Schema create(SchemaPlus parentSchema, String name,
-      Map<String, Object> operand) {
-    final Map map = (Map) operand;
-
-    final ObjectMapper mapper = new ObjectMapper();
-    mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
-
-    try {
-      final Map<String, Integer> coordinates =
-          mapper.readValue((String) map.get("coordinates"),
-              new TypeReference<Map<String, Integer>>() { });
-      final Map<String, String> userConfig =
-          mapper.readValue((String) map.get("userConfig"),
-              new TypeReference<Map<String, String>>() { });
-      final String index = (String) map.get("index");
-      return new Elasticsearch2Schema(coordinates, userConfig, index);
-    } catch (IOException e) {
-      throw new RuntimeException("Cannot parse values from json", e);
-    }
-  }
-}
-
-// End Elasticsearch2SchemaFactory.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Table.java
----------------------------------------------------------------------
diff --git a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Table.java b/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Table.java
deleted file mode 100644
index 8bfd8cf..0000000
--- a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/Elasticsearch2Table.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.calcite.adapter.elasticsearch2;
-
-import org.apache.calcite.adapter.elasticsearch.AbstractElasticsearchTable;
-import org.apache.calcite.linq4j.AbstractEnumerable;
-import org.apache.calcite.linq4j.Enumerable;
-import org.apache.calcite.linq4j.Enumerator;
-import org.apache.calcite.linq4j.function.Function1;
-
-import org.apache.calcite.util.Util;
-
-import org.elasticsearch.client.Client;
-import org.elasticsearch.search.SearchHit;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Table based on an Elasticsearch2 type.
- */
-public class Elasticsearch2Table extends AbstractElasticsearchTable {
-  private final Client client;
-
-  /**
-   * Creates an Elasticsearch2Table.
-   *
-   * @param client Existing ES instance
-   * @param indexName Name of the index
-   * @param typeName Index type
-   */
-  Elasticsearch2Table(Client client, String indexName, String typeName) {
-    super(indexName, typeName);
-    this.client = client;
-  }
-
-  /**
-   * ES version 2.x. To access document attributes ES2 uses {@code _source.foo} syntax.
-   */
-  @Override protected String scriptedFieldPrefix() {
-    return "_source";
-  }
-
-  @Override protected Enumerable<Object> find(String index, List<String> ops,
-                                              List<Map.Entry<String, Class>> fields) {
-    final String dbName = index;
-
-    final String queryString = "{" + Util.toString(ops, "", ", ", "") + "}";
-
-    final Function1<SearchHit, Object> getter = Elasticsearch2Enumerator.getter(fields);
-
-    return new AbstractEnumerable<Object>() {
-      public Enumerator<Object> enumerator() {
-        final Iterator<SearchHit> cursor = client.prepareSearch(dbName).setTypes(typeName)
-            .setSource(queryString).execute().actionGet().getHits().iterator();
-        return new Elasticsearch2Enumerator(cursor, getter);
-      }
-    };
-  }
-}
-
-// End Elasticsearch2Table.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/0204f286/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/package-info.java
----------------------------------------------------------------------
diff --git a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/package-info.java b/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/package-info.java
deleted file mode 100644
index a1c10c9..0000000
--- a/elasticsearch2/src/main/java/org/apache/calcite/adapter/elasticsearch2/package-info.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Query provider based on an Elasticsearch2 DB.
- */
-@PackageMarker
-package org.apache.calcite.adapter.elasticsearch2;
-
-import org.apache.calcite.avatica.util.PackageMarker;
-
-// End package-info.java