You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zipkin.apache.org by ad...@apache.org on 2019/05/07 06:57:53 UTC

[incubator-zipkin] branch conditional-es-wrap created (now b13078b)

This is an automated email from the ASF dual-hosted git repository.

adriancole pushed a change to branch conditional-es-wrap
in repository https://gitbox.apache.org/repos/asf/incubator-zipkin.git.


      at b13078b  Conditionally wraps in Elasticsearch index template based on version

This branch includes the following new commits:

     new b13078b  Conditionally wraps in Elasticsearch index template based on version

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[incubator-zipkin] 01/01: Conditionally wraps in Elasticsearch index template based on version

Posted by ad...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

adriancole pushed a commit to branch conditional-es-wrap
in repository https://gitbox.apache.org/repos/asf/incubator-zipkin.git

commit b13078b38257b166c0202c09c13c30b7f3046902
Author: Adrian Cole <ac...@pivotal.io>
AuthorDate: Tue May 7 14:55:28 2019 +0800

    Conditionally wraps in Elasticsearch index template based on version
    
    Elasticsearch 7.x no longer wraps mappings by top-level type. They have
    a compatibility mode, but it complicates secondary templates as noticed
    by @chefky
    
    > For my custom index issue in elasticsearch 7.0 -- I figured it out, but I think it does have an implication with the code. You are still creating the index template with the mapping type, which ElasticSearch has deprecated in 7.0. When I do a 'GET /_template/zipkin-span_template', the mapping type 'span' is removed, and so my updated version did not include the mapping type. I can only get it to work by including the mapping type 'span' in my updated index template, but I have to ap [...]
    
    This addresses the issue depending on the version of Elasticsearch in
    use.
    
    Fixes #2559
---
 .../elasticsearch/ElasticsearchSpanConsumer.java   |   5 +-
 .../elasticsearch/ElasticsearchStorage.java        |   4 +-
 .../elasticsearch/VersionSpecificTemplates.java    | 225 ++++++++++-----------
 .../elasticsearch/internal/HttpBulkIndexer.java    |   6 +-
 .../VersionSpecificTemplatesTest.java              |  83 +++++++-
 5 files changed, 193 insertions(+), 130 deletions(-)

diff --git a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchSpanConsumer.java b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchSpanConsumer.java
index e793394..1bbf27a 100644
--- a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchSpanConsumer.java
+++ b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchSpanConsumer.java
@@ -87,9 +87,8 @@ class ElasticsearchSpanConsumer implements SpanConsumer { // not final for testi
       } else {
         // guessTimestamp is made for determining the span's authoritative timestamp. When choosing
         // the index bucket, any annotation is better than using current time.
-        for (int i = 0, length = span.annotations().size(); i < length; i++) {
-          indexTimestamp = span.annotations().get(i).timestamp() / 1000;
-          break;
+        if (!span.annotations().isEmpty()) {
+          indexTimestamp = span.annotations().get(0).timestamp() / 1000;
         }
         if (indexTimestamp == 0L) indexTimestamp = System.currentTimeMillis();
       }
diff --git a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java
index 1d12681..974f9ce 100644
--- a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java
+++ b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/ElasticsearchStorage.java
@@ -342,7 +342,7 @@ public abstract class ElasticsearchStorage extends zipkin2.storage.StorageCompon
   @Memoized // since we don't want overlapping calls to apply the index templates
   IndexTemplates ensureIndexTemplates() {
     try {
-      IndexTemplates templates = new VersionSpecificTemplates(this).get(http());
+      IndexTemplates templates = new VersionSpecificTemplates(this).get();
       HttpCall.Factory http = http();
       ensureIndexTemplate(http, buildUrl(http, templates, SPAN), templates.span());
       ensureIndexTemplate(http, buildUrl(http, templates, DEPENDENCY), templates.dependency());
@@ -355,8 +355,6 @@ public abstract class ElasticsearchStorage extends zipkin2.storage.StorageCompon
 
   HttpUrl buildUrl(HttpCall.Factory http, IndexTemplates templates, String type) {
     HttpUrl.Builder builder = http.baseUrl.newBuilder("_template");
-    // ES 7.x defaults include_type_name to false https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#_literal_include_type_name_literal_now_defaults_to_literal_false_literal
-    if (templates.version() >= 7) builder.addQueryParameter("include_type_name", "true");
     String indexPrefix = indexNameFormatter().index() + templates.indexTypeDelimiter();
     return builder.addPathSegment(indexPrefix + type + "_template").build();
   }
diff --git a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/VersionSpecificTemplates.java b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/VersionSpecificTemplates.java
index 244aa87..ee522bb 100644
--- a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/VersionSpecificTemplates.java
+++ b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/VersionSpecificTemplates.java
@@ -22,6 +22,9 @@ import okhttp3.Request;
 import okio.BufferedSource;
 import zipkin2.elasticsearch.internal.client.HttpCall;
 
+import static zipkin2.elasticsearch.ElasticsearchAutocompleteTags.AUTOCOMPLETE;
+import static zipkin2.elasticsearch.ElasticsearchSpanStore.DEPENDENCY;
+import static zipkin2.elasticsearch.ElasticsearchSpanStore.SPAN;
 import static zipkin2.elasticsearch.internal.JsonReaders.enterPath;
 
 /** Returns a version-specific span and dependency index template */
@@ -32,45 +35,50 @@ final class VersionSpecificTemplates {
    */
   static final String KEYWORD = "{ \"type\": \"keyword\", \"norms\": false }";
 
-  final boolean searchEnabled, strictTraceId;
-  final String spanIndexTemplate;
-  final String dependencyIndexTemplate;
-  final String autocompleteIndexTemplate;
+  final ElasticsearchStorage es;
 
   VersionSpecificTemplates(ElasticsearchStorage es) {
-    this.searchEnabled = es.searchEnabled();
-    this.strictTraceId = es.strictTraceId();
-    this.spanIndexTemplate = spanIndexTemplate()
-      .replace("${INDEX}", es.indexNameFormatter().index())
-      .replace("${NUMBER_OF_SHARDS}", String.valueOf(es.indexShards()))
-      .replace("${NUMBER_OF_REPLICAS}", String.valueOf(es.indexReplicas()))
-      .replace("${TRACE_ID_MAPPING}", strictTraceId ? KEYWORD
-        // Supporting mixed trace ID length is expensive due to needing a special analyzer and
-        // "fielddata" which consumes a lot of heap. Sites should only turn off strict trace ID when
-        // in a transition, and keep trace ID length transitions as short time as possible.
-        : "{ \"type\": \"text\", \"fielddata\": \"true\", \"analyzer\": \"traceId_analyzer\" }");
-    this.dependencyIndexTemplate = DEPENDENCY_INDEX_TEMPLATE
-      .replace("${INDEX}", es.indexNameFormatter().index())
-      .replace("${NUMBER_OF_SHARDS}", String.valueOf(es.indexShards()))
-      .replace("${NUMBER_OF_REPLICAS}", String.valueOf(es.indexReplicas()));
-    this.autocompleteIndexTemplate = AUTOCOMPLETE_INDEX_TEMPLATE
-      .replace("${INDEX}", es.indexNameFormatter().index())
-      .replace("${NUMBER_OF_SHARDS}", String.valueOf(es.indexShards()))
-      .replace("${NUMBER_OF_REPLICAS}", String.valueOf(es.indexReplicas()));
+    this.es = es;
   }
 
-  /** Templatized due to version differences. Only fields used in search are declared */
-  String spanIndexTemplate() {
+  String indexPattern(String type, float version) {
+    return new StringBuilder()
+      .append('"')
+      .append(version < 6.0f ? "template" : "index_patterns")
+      .append("\": \"")
+      .append(es.indexNameFormatter().index())
+      .append(indexTypeDelimiter(version))
+      .append(type)
+      .append("-*")
+      .append("\"").toString();
+  }
+
+  String indexProperties(float version) {
+    // 6.x _all disabled https://www.elastic.co/guide/en/elasticsearch/reference/6.7/breaking-changes-6.0.html#_the_literal__all_literal_meta_field_is_now_disabled_by_default
+    // 7.x _default disallowed https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#_the_literal__default__literal_mapping_is_no_longer_allowed
     String result = ""
-      + "{\n"
-      + "  \"index_patterns\": \"${INDEX}${INDEX_TYPE_DELIMITER}span-*\",\n"
-      + "  \"settings\": {\n"
-      + "    \"index.number_of_shards\": ${NUMBER_OF_SHARDS},\n"
-      + "    \"index.number_of_replicas\": ${NUMBER_OF_REPLICAS},\n"
-      + "    \"index.requests.cache.enable\": true,\n"
-      + "    \"index.mapper.dynamic\": false";
+      + "    \"index.number_of_shards\": " + es.indexShards() + ",\n"
+      + "    \"index.number_of_replicas\": " + es.indexReplicas() + ",\n"
+      + "    \"index.requests.cache.enable\": true";
+    // There is no explicit documentation of index.mapper.dynamic being removed in v7, but it was.
+    if (version >= 7.0f) return result + "\n";
+    return result + (",\n    \"index.mapper.dynamic\": false\n");
+  }
 
-    if (!strictTraceId) {
+  /** Templatized due to version differences. Only fields used in search are declared */
+  String spanIndexTemplate(float version) {
+    String result = "{\n"
+      + "  " + indexPattern(SPAN, version) + ",\n"
+      + "  \"settings\": {\n"
+      + indexProperties(version);
+
+    String traceIdMapping = KEYWORD;
+    if (!es.strictTraceId()) {
+      // Supporting mixed trace ID length is expensive due to needing a special analyzer and
+      // "fielddata" which consumes a lot of heap. Sites should only turn off strict trace ID when
+      // in a transition, and keep trace ID length transitions as short time as possible.
+      traceIdMapping =
+        "{ \"type\": \"text\", \"fielddata\": \"true\", \"analyzer\": \"traceId_analyzer\" }";
       result += (",\n"
         + "    \"analysis\": {\n"
         + "      \"analyzer\": {\n"
@@ -92,97 +100,93 @@ final class VersionSpecificTemplates {
 
     result += "  },\n";
 
-    if (searchEnabled) {
+    if (es.searchEnabled()) {
       return result
         + ("  \"mappings\": {\n"
-        + "    \"span\": {\n"
-        + "      \"_source\": {\"excludes\": [\"_q\"] },\n"
-        + "      \"dynamic_templates\": [\n"
-        + "        {\n"
-        + "          \"strings\": {\n"
-        + "            \"mapping\": {\n"
-        + "              \"type\": \"keyword\",\"norms\": false,\n"
-        + "              \"ignore_above\": 256\n"
-        + "            },\n"
-        + "            \"match_mapping_type\": \"string\",\n"
-        + "            \"match\": \"*\"\n"
-        + "          }\n"
+        + maybeWrap(SPAN, version, ""
+        + "    \"_source\": {\"excludes\": [\"_q\"] },\n"
+        + "    \"dynamic_templates\": [\n"
+        + "      {\n"
+        + "        \"strings\": {\n"
+        + "          \"mapping\": {\n"
+        + "            \"type\": \"keyword\",\"norms\": false, \"ignore_above\": 256\n"
+        + "          },\n"
+        + "          \"match_mapping_type\": \"string\",\n"
+        + "          \"match\": \"*\"\n"
         + "        }\n"
-        + "      ],\n"
-        + "      \"properties\": {\n"
-        + "        \"traceId\": ${TRACE_ID_MAPPING},\n"
-        + "        \"name\": " + KEYWORD + ",\n"
-        + "        \"localEndpoint\": {\n"
-        + "          \"type\": \"object\",\n"
-        + "          \"dynamic\": false,\n"
-        + "          \"properties\": { \"serviceName\": " + KEYWORD + " }\n"
-        + "        },\n"
-        + "        \"remoteEndpoint\": {\n"
-        + "          \"type\": \"object\",\n"
-        + "          \"dynamic\": false,\n"
-        + "          \"properties\": { \"serviceName\": " + KEYWORD + " }\n"
-        + "        },\n"
-        + "        \"timestamp_millis\": {\n"
-        + "          \"type\":   \"date\",\n"
-        + "          \"format\": \"epoch_millis\"\n"
-        + "        },\n"
-        + "        \"duration\": { \"type\": \"long\" },\n"
-        + "        \"annotations\": { \"enabled\": false },\n"
-        + "        \"tags\": { \"enabled\": false },\n"
-        + "        \"_q\": " + KEYWORD + "\n"
         + "      }\n"
-        + "    }\n"
+        + "    ],\n"
+        + "    \"properties\": {\n"
+        + "      \"traceId\": " + traceIdMapping + ",\n"
+        + "      \"name\": " + KEYWORD + ",\n"
+        + "      \"localEndpoint\": {\n"
+        + "        \"type\": \"object\",\n"
+        + "        \"dynamic\": false,\n"
+        + "        \"properties\": { \"serviceName\": " + KEYWORD + " }\n"
+        + "      },\n"
+        + "      \"remoteEndpoint\": {\n"
+        + "        \"type\": \"object\",\n"
+        + "        \"dynamic\": false,\n"
+        + "        \"properties\": { \"serviceName\": " + KEYWORD + " }\n"
+        + "      },\n"
+        + "      \"timestamp_millis\": {\n"
+        + "        \"type\":   \"date\",\n"
+        + "        \"format\": \"epoch_millis\"\n"
+        + "      },\n"
+        + "      \"duration\": { \"type\": \"long\" },\n"
+        + "      \"annotations\": { \"enabled\": false },\n"
+        + "      \"tags\": { \"enabled\": false },\n"
+        + "      \"_q\": " + KEYWORD + "\n"
+        + "    }\n")
         + "  }\n"
         + "}");
     }
     return result
       + ("  \"mappings\": {\n"
-      + "    \"span\": {\n"
-      + "      \"properties\": {\n"
-      + "        \"traceId\": ${TRACE_ID_MAPPING},\n"
-      + "        \"annotations\": { \"enabled\": false },\n"
-      + "        \"tags\": { \"enabled\": false }\n"
-      + "      }\n"
-      + "    }\n"
+      + maybeWrap(SPAN, version, ""
+      + "    \"properties\": {\n"
+      + "      \"traceId\": " + traceIdMapping + ",\n"
+      + "      \"annotations\": { \"enabled\": false },\n"
+      + "      \"tags\": { \"enabled\": false }\n"
+      + "    }\n")
       + "  }\n"
       + "}");
   }
 
   /** Templatized due to version differences. Only fields used in search are declared */
-  static final String DEPENDENCY_INDEX_TEMPLATE =
-    "{\n"
-      + "  \"index_patterns\": \"${INDEX}${INDEX_TYPE_DELIMITER}dependency-*\",\n"
+  String dependencyTemplate(float version) {
+    return "{\n"
+      + "  " + indexPattern(DEPENDENCY, version) + ",\n"
       + "  \"settings\": {\n"
-      + "    \"index.number_of_shards\": ${NUMBER_OF_SHARDS},\n"
-      + "    \"index.number_of_replicas\": ${NUMBER_OF_REPLICAS},\n"
-      + "    \"index.requests.cache.enable\": true,\n"
-      + "    \"index.mapper.dynamic\": false\n"
+      + indexProperties(version)
       + "  },\n"
-      + "  \"mappings\": {\"dependency\": { \"enabled\": false }}\n"
+      + "  \"mappings\": {\n"
+      + maybeWrap(DEPENDENCY, version, "    \"enabled\": false\n")
+      + "  }\n"
       + "}";
+  }
 
   // The key filed of a autocompleteKeys is intentionally names as tagKey since it clashes with the
   // BodyConverters KEY
-  static final String AUTOCOMPLETE_INDEX_TEMPLATE =
-    "{\n"
-      + "  \"index_patterns\": \"${INDEX}${INDEX_TYPE_DELIMITER}autocomplete-*\",\n"
+  String autocompleteTemplate(float version) {
+    return "{\n"
+      + "  " + indexPattern(AUTOCOMPLETE, version) + ",\n"
       + "  \"settings\": {\n"
-      + "    \"index.number_of_shards\": ${NUMBER_OF_SHARDS},\n"
-      + "    \"index.number_of_replicas\": ${NUMBER_OF_REPLICAS},\n"
-      + "    \"index.requests.cache.enable\": true,\n"
-      + "    \"index.mapper.dynamic\": false\n"
+      + indexProperties(version)
       + "  },\n"
       + "  \"mappings\": {\n"
-      + "   \"autocomplete\": {\n"
-      + "      \"enabled\": true,\n"
-      + "      \"properties\": {\n"
-      + "        \"tagKey\": " + KEYWORD + ",\n"
-      + "        \"tagValue\": " + KEYWORD + "\n"
-      + "  }}}\n"
+      + maybeWrap(AUTOCOMPLETE, version, ""
+      + "    \"enabled\": true,\n"
+      + "    \"properties\": {\n"
+      + "      \"tagKey\": " + KEYWORD + ",\n"
+      + "      \"tagValue\": " + KEYWORD + "\n"
+      + "    }\n")
+      + "  }\n"
       + "}";
+  }
 
-  IndexTemplates get(HttpCall.Factory callFactory) throws IOException {
-    float version = getVersion(callFactory);
+  IndexTemplates get() throws IOException {
+    float version = getVersion(es.http());
     if (version < 5.0f || version >= 8.0f) {
       throw new IllegalArgumentException(
         "Elasticsearch versions 5-7.x are supported, was: " + version);
@@ -190,9 +194,9 @@ final class VersionSpecificTemplates {
     return IndexTemplates.newBuilder()
       .version(version)
       .indexTypeDelimiter(indexTypeDelimiter(version))
-      .span(versionSpecificIndexTemplate(spanIndexTemplate, version))
-      .dependency(versionSpecificIndexTemplate(dependencyIndexTemplate, version))
-      .autocomplete(versionSpecificIndexTemplate(autocompleteIndexTemplate, version))
+      .span(spanIndexTemplate(version))
+      .dependency(dependencyTemplate(version))
+      .autocomplete(autocompleteTemplate(version))
       .build();
   }
 
@@ -208,6 +212,12 @@ final class VersionSpecificTemplates {
     return version < 7.0f ? ':' : '-';
   }
 
+  static String maybeWrap(String type, float version, String json) {
+    // ES 7.x defaults include_type_name to false https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#_literal_include_type_name_literal_now_defaults_to_literal_false_literal
+    if (version >= 7.0f) return json;
+    return "    \"" + type + "\": {\n  " + json.replace("\n", "\n  ") + "  }\n";
+  }
+
   static float getVersion(HttpCall.Factory callFactory) throws IOException {
     Request getNode = new Request.Builder().url(callFactory.baseUrl).tag("get-node").build();
     return callFactory.newCall(getNode, ReadVersionNumber.INSTANCE).execute();
@@ -223,16 +233,5 @@ final class VersionSpecificTemplates {
       return Float.valueOf(versionString.substring(0, 3));
     }
   }
-
-  static String versionSpecificIndexTemplate(String template, float version) {
-    String indexTypeDelimiter = Character.toString(indexTypeDelimiter(version));
-    template = template.replace("${INDEX_TYPE_DELIMITER}", indexTypeDelimiter);
-    if (version < 6.0f) return template.replace("index_patterns", "template");
-    // 6.x _all disabled https://www.elastic.co/guide/en/elasticsearch/reference/6.7/breaking-changes-6.0.html#_the_literal__all_literal_meta_field_is_now_disabled_by_default
-    // 7.x _default disallowed https://www.elastic.co/guide/en/elasticsearch/reference/current/breaking-changes-7.0.html#_the_literal__default__literal_mapping_is_no_longer_allowed
-    if (version < 7.0f) return template;
-    // There is no explicit documentation of this setting being removed in 7.0f, but it was.
-    return template.replace(",\n    \"index.mapper.dynamic\": false", "");
-  }
 }
 
diff --git a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/HttpBulkIndexer.java b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/HttpBulkIndexer.java
index c52cda1..2eeffea 100644
--- a/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/HttpBulkIndexer.java
+++ b/zipkin-storage/elasticsearch/src/main/java/zipkin2/elasticsearch/internal/HttpBulkIndexer.java
@@ -36,6 +36,7 @@ public final class HttpBulkIndexer {
   static final MediaType APPLICATION_JSON = MediaType.parse("application/json");
 
   final String tag;
+  final boolean shouldAddType;
   final HttpCall.Factory http;
   final String pipeline;
   final boolean waitForRefresh;
@@ -45,6 +46,7 @@ public final class HttpBulkIndexer {
 
   public HttpBulkIndexer(String tag, ElasticsearchStorage es) {
     this.tag = tag;
+    shouldAddType = es.version() < 7.0f;
     http = es.http();
     pipeline = es.pipeline();
     waitForRefresh = es.flushOnWrites();
@@ -74,8 +76,8 @@ public final class HttpBulkIndexer {
 
   void writeIndexMetadata(String index, String typeName, @Nullable String id) {
     body.writeUtf8("{\"index\":{\"_index\":\"").writeUtf8(index).writeByte('"');
-    // the _type parameter is needed for Elasticsearch <6.x
-    body.writeUtf8(",\"_type\":\"").writeUtf8(typeName).writeByte('"');
+    // the _type parameter is needed for Elasticsearch < 6.x
+    if (shouldAddType) body.writeUtf8(",\"_type\":\"").writeUtf8(typeName).writeByte('"');
     if (id != null) {
       body.writeUtf8(",\"_id\":\"").writeUtf8(jsonEscape(id).toString()).writeByte('"');
     }
diff --git a/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/VersionSpecificTemplatesTest.java b/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/VersionSpecificTemplatesTest.java
index 0636403..164db5b 100644
--- a/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/VersionSpecificTemplatesTest.java
+++ b/zipkin-storage/elasticsearch/src/test/java/zipkin2/elasticsearch/VersionSpecificTemplatesTest.java
@@ -107,13 +107,13 @@ public class VersionSpecificTemplatesTest {
 
     thrown.expectMessage("Elasticsearch versions 5-7.x are supported, was: 2.4");
 
-    new VersionSpecificTemplates(storage).get(storage.http());
+    new VersionSpecificTemplates(storage).get();
   }
 
   @Test public void version5() throws Exception {
     es.enqueue(VERSION_RESPONSE_5);
 
-    IndexTemplates template = new VersionSpecificTemplates(storage).get(storage.http());
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
 
     assertThat(template.version()).isEqualTo(5.0f);
     assertThat(template.autocomplete())
@@ -129,7 +129,7 @@ public class VersionSpecificTemplatesTest {
   @Test public void version6() throws Exception {
     es.enqueue(VERSION_RESPONSE_6);
 
-    IndexTemplates template = new VersionSpecificTemplates(storage).get(storage.http());
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
 
     assertThat(template.version()).isEqualTo(6.7f);
     assertThat(template.autocomplete())
@@ -139,28 +139,72 @@ public class VersionSpecificTemplatesTest {
       .contains("\"index.mapper.dynamic\": false");
   }
 
+  @Test public void version6_wrapsPropertiesWithType() throws Exception {
+    es.enqueue(VERSION_RESPONSE_6);
+
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
+
+    assertThat(template.dependency()).contains(""
+      + "  \"mappings\": {\n"
+      + "    \"dependency\": {\n"
+      + "      \"enabled\": false\n"
+      + "    }\n"
+      + "  }");
+
+    assertThat(template.autocomplete()).contains(""
+      + "  \"mappings\": {\n"
+      + "    \"autocomplete\": {\n"
+      + "      \"enabled\": true,\n"
+      + "      \"properties\": {\n"
+      + "        \"tagKey\": { \"type\": \"keyword\", \"norms\": false },\n"
+      + "        \"tagValue\": { \"type\": \"keyword\", \"norms\": false }\n"
+      + "      }\n"
+      + "    }\n"
+      + "  }");
+  }
+
   @Test public void version7() throws Exception {
     es.enqueue(VERSION_RESPONSE_7);
 
-    IndexTemplates template = new VersionSpecificTemplates(storage).get(storage.http());
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
 
     assertThat(template.version()).isEqualTo(7.0f);
     assertThat(template.autocomplete())
       .withFailMessage("Starting at v7.x, we delimit index and type with hyphen")
       .contains("\"index_patterns\": \"zipkin-autocomplete-*\"");
     assertThat(template.autocomplete())
-      //.withFailMessage("7.x does not support the key index.mapper.dynamic")
+      .withFailMessage("7.x does not support the key index.mapper.dynamic")
       .doesNotContain("\"index.mapper.dynamic\": false");
   }
 
-  @Test public void searchEnabled_minimalSpanIndexing() throws Exception {
+  @Test public void version7_doesntWrapPropertiesWithType() throws Exception {
+    es.enqueue(VERSION_RESPONSE_7);
+
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
+
+    assertThat(template.dependency()).contains(""
+      + "  \"mappings\": {\n"
+      + "    \"enabled\": false\n"
+      + "  }");
+
+    assertThat(template.autocomplete()).contains(""
+      + "  \"mappings\": {\n"
+      + "    \"enabled\": true,\n"
+      + "    \"properties\": {\n"
+      + "      \"tagKey\": { \"type\": \"keyword\", \"norms\": false },\n"
+      + "      \"tagValue\": { \"type\": \"keyword\", \"norms\": false }\n"
+      + "    }\n"
+      + "  }");
+  }
+
+  @Test public void searchEnabled_minimalSpanIndexing_6x() throws Exception {
     storage = ElasticsearchStorage.newBuilder().hosts(storage.hostsSupplier().get())
       .searchEnabled(false)
       .build();
 
     es.enqueue(VERSION_RESPONSE_6);
 
-    IndexTemplates template = new VersionSpecificTemplates(storage).get(storage.http());
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
 
     assertThat(template.span())
       .contains(""
@@ -175,10 +219,31 @@ public class VersionSpecificTemplatesTest {
         + "  }");
   }
 
+  @Test public void searchEnabled_minimalSpanIndexing_7x() throws Exception {
+    storage = ElasticsearchStorage.newBuilder().hosts(storage.hostsSupplier().get())
+      .searchEnabled(false)
+      .build();
+
+    es.enqueue(VERSION_RESPONSE_7);
+
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
+
+    // doesn't wrap in a type name
+    assertThat(template.span())
+      .contains(""
+        + "  \"mappings\": {\n"
+        + "    \"properties\": {\n"
+        + "      \"traceId\": { \"type\": \"keyword\", \"norms\": false },\n"
+        + "      \"annotations\": { \"enabled\": false },\n"
+        + "      \"tags\": { \"enabled\": false }\n"
+        + "    }\n"
+        + "  }");
+  }
+
   @Test public void strictTraceId_doesNotIncludeAnalysisSection() throws Exception {
     es.enqueue(VERSION_RESPONSE_6);
 
-    IndexTemplates template = new VersionSpecificTemplates(storage).get(storage.http());
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
 
     assertThat(template.span()).doesNotContain("analysis");
   }
@@ -190,7 +255,7 @@ public class VersionSpecificTemplatesTest {
 
     es.enqueue(VERSION_RESPONSE_6);
 
-    IndexTemplates template = new VersionSpecificTemplates(storage).get(storage.http());
+    IndexTemplates template = new VersionSpecificTemplates(storage).get();
 
     assertThat(template.span()).contains("analysis");
   }