Skip to content

Commit

Permalink
Adding deprecation info API message for sparse_vector (#77381)
Browse files Browse the repository at this point in the history
The sparse_vector type is deprecated and has been removed in 8.0. This commit adds a deprecation info API
message if we detect templates with mappings that include sparse_vector fields.
Relates #42404 #48781
  • Loading branch information
masseyke authored Sep 7, 2021
1 parent f586405 commit bbe4c48
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,95 @@ static DeprecationIssue checkGeoShapeTemplates(final ClusterState clusterState)
return null;
}
}

protected static boolean isSparseVector(Map<?, ?> property) {
return "sparse_vector".equals(property.get("type"));
}

protected static String formatDeprecatedSparseVectorMessage(String type, Map.Entry<?, ?> entry) {
return entry.getKey().toString();
}

@SuppressWarnings("unchecked")
private static String getDetailsMessageForSparseVectorComponentTemplates(Map<String, ComponentTemplate> componentTemplates) {
String detailsForComponentTemplates =
componentTemplates.entrySet().stream().map((templateCursor) -> {
String templateName = templateCursor.getKey();
ComponentTemplate componentTemplate = templateCursor.getValue();
CompressedXContent mappings = componentTemplate.template().mappings();
if (mappings != null) {
Tuple<XContentType, Map<String, Object>> tuple = XContentHelper.convertToMap(mappings.uncompressed(), true,
XContentType.JSON);
Map<String, Object> mappingAsMap = tuple.v2();
List<String> messages = mappingAsMap == null ? Collections.emptyList() :
IndexDeprecationChecks.findInPropertiesRecursively(LegacyGeoShapeFieldMapper.CONTENT_TYPE,
mappingAsMap,
ClusterDeprecationChecks::isSparseVector,
ClusterDeprecationChecks::formatDeprecatedSparseVectorMessage);
if (messages.isEmpty() == false) {
String messageForMapping =
"mappings in component template [" + templateName + "] contains deprecated sparse_vector fields: " +
messages.stream().collect(Collectors.joining(", "));
return messageForMapping;
}
}
return null;
}).filter(messageForTemplate -> Strings.isEmpty(messageForTemplate) == false).collect(Collectors.joining("; "));
return detailsForComponentTemplates;
}

@SuppressWarnings("unchecked")
private static String getDetailsMessageForSparseVectorIndexTemplates(ImmutableOpenMap<String, IndexTemplateMetadata> indexTemplates) {
String detailsForIndexTemplates =
StreamSupport.stream(indexTemplates.spliterator(), false).map((templateCursor) -> {
String templateName = templateCursor.key;
IndexTemplateMetadata indexTemplateMetadata = templateCursor.value;
String messageForTemplate =
StreamSupport.stream(indexTemplateMetadata.getMappings().spliterator(), false).map((mappingCursor) -> {
CompressedXContent mapping = mappingCursor.value;
Tuple<XContentType, Map<String, Object>> tuple = XContentHelper.convertToMap(mapping.uncompressed(), true,
XContentType.JSON);
Map<String, Object> mappingAsMap = (Map<String, Object>) tuple.v2().get("_doc");
List<String> messages = mappingAsMap == null ? Collections.emptyList() :
IndexDeprecationChecks.findInPropertiesRecursively(LegacyGeoShapeFieldMapper.CONTENT_TYPE,
mappingAsMap,
ClusterDeprecationChecks::isSparseVector,
ClusterDeprecationChecks::formatDeprecatedSparseVectorMessage);
return messages;
}).filter(messages -> messages.isEmpty() == false).map(messages -> {
String messageForMapping =
"mappings in index template " + templateName + " contains deprecated sparse_vector fields: " +
messages.stream().collect(Collectors.joining(", "));
return messageForMapping;
}).collect(Collectors.joining("; "));
return messageForTemplate;
}).filter(messageForTemplate -> Strings.isEmpty(messageForTemplate) == false).collect(Collectors.joining("; "));
return detailsForIndexTemplates;
}

@SuppressWarnings("unchecked")
static DeprecationIssue checkSparseVectorTemplates(final ClusterState clusterState) {
String detailsForComponentTemplates =
getDetailsMessageForSparseVectorComponentTemplates(clusterState.getMetadata().componentTemplates());
String detailsForIndexTemplates = getDetailsMessageForSparseVectorIndexTemplates(clusterState.getMetadata().getTemplates());
boolean deprecationInComponentTemplates = Strings.isEmpty(detailsForComponentTemplates) == false;
boolean deprecationInIndexTemplates = Strings.isEmpty(detailsForIndexTemplates) == false;
String url = "https://www.elastic.co/guide/en/elasticsearch/reference/master/migrating-8.0.html#breaking_80_search_changes";
if (deprecationInComponentTemplates && deprecationInIndexTemplates) {
String message = "component templates and index templates contain deprecated sparse_vector fields that must be removed";
String details = detailsForComponentTemplates + "; " + detailsForIndexTemplates;
return new DeprecationIssue(DeprecationIssue.Level.CRITICAL, message, url, details, false,
null);
} if (deprecationInComponentTemplates == false && deprecationInIndexTemplates) {
String message = "index templates contain deprecated sparse_vector fields that must be removed";
return new DeprecationIssue(DeprecationIssue.Level.CRITICAL, message, url, detailsForIndexTemplates, false,
null);
} else if (deprecationInIndexTemplates == false && deprecationInComponentTemplates) {
String message = "component templates contain deprecated sparse_vector fields that must be removed";
return new DeprecationIssue(DeprecationIssue.Level.CRITICAL, message, url, detailsForComponentTemplates, false,
null);
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ private DeprecationChecks() {
ClusterDeprecationChecks::checkTemplatesWithFieldNamesDisabled,
ClusterDeprecationChecks::checkTemplatesWithMultipleTypes,
ClusterDeprecationChecks::checkClusterRoutingAllocationIncludeRelocationsSetting,
ClusterDeprecationChecks::checkGeoShapeTemplates
ClusterDeprecationChecks::checkGeoShapeTemplates,
ClusterDeprecationChecks::checkSparseVectorTemplates
));

static final List<NodeDeprecationCheck<Settings, PluginsAndModules, ClusterState, XPackLicenseState, DeprecationIssue>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,4 +439,81 @@ public void testCheckGeoShapeMappings() throws Exception {
"[location]]", false, null)
));
}

public void testSparseVectorMappings() throws Exception {
// First, testing only an index template:
IndexTemplateMetadata indexTemplateMetadata = IndexTemplateMetadata.builder("single-type")
.patterns(Collections.singletonList("foo"))
.putMapping("_doc", "{\n" +
" \"_doc\":{\n" +
" \"properties\":{\n" +
" \"my_sparse_vector\":{\n" +
" \"type\":\"sparse_vector\"\n" +
" },\n" +
" \"nested_field\":{\n" +
" \"type\":\"nested\",\n" +
" \"properties\":{\n" +
" \"my_nested_sparse_vector\":{\n" +
" \"type\":\"sparse_vector\"\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
"}")
.build();
ImmutableOpenMap<String, IndexTemplateMetadata> templates = ImmutableOpenMap.<String, IndexTemplateMetadata>builder()
.fPut("single-type", indexTemplateMetadata)
.build();
Metadata badMetadata = Metadata.builder()
.templates(templates)
.build();
ClusterState badState = ClusterState.builder(new ClusterName("test")).metadata(badMetadata).build();
DeprecationIssue issue = ClusterDeprecationChecks.checkSparseVectorTemplates(badState);

assertThat(issue, equalTo(
new DeprecationIssue(DeprecationIssue.Level.CRITICAL,
"index templates contain deprecated sparse_vector fields that must be removed",
"https://www.elastic.co/guide/en/elasticsearch/reference/master/migrating-8.0.html#breaking_80_search_changes",
"mappings in index template single-type contains deprecated sparse_vector fields: [my_sparse_vector], " +
"[my_nested_sparse_vector]", false, null)
));

// Second, testing only a component template:
String templateName = "my-template";
Settings settings = Settings.builder().put("index.number_of_shards", 1).build();
CompressedXContent mappings = new CompressedXContent("{\"properties\":{\"my_sparse_vector\":{\"type\":\"sparse_vector\"}}}");
AliasMetadata alias = AliasMetadata.builder("alias").writeIndex(true).build();
Template template = new Template(settings, mappings, Collections.singletonMap("alias", alias));
ComponentTemplate componentTemplate = new ComponentTemplate(template, 1L, new HashMap<>());
badMetadata = Metadata.builder()
.componentTemplates(Collections.singletonMap(templateName, componentTemplate))
.build();
badState = ClusterState.builder(new ClusterName("test")).metadata(badMetadata).build();
issue = ClusterDeprecationChecks.checkSparseVectorTemplates(badState);

assertThat(issue, equalTo(
new DeprecationIssue(DeprecationIssue.Level.CRITICAL,
"component templates contain deprecated sparse_vector fields that must be removed",
"https://www.elastic.co/guide/en/elasticsearch/reference/master/migrating-8.0.html#breaking_80_search_changes",
"mappings in component template [my-template] contains deprecated sparse_vector fields: [my_sparse_vector]", false, null)
));

// Third, trying a component template and an index template:
badMetadata = Metadata.builder()
.componentTemplates(Collections.singletonMap(templateName, componentTemplate))
.templates(templates)
.build();
badState = ClusterState.builder(new ClusterName("test")).metadata(badMetadata).build();
issue = ClusterDeprecationChecks.checkSparseVectorTemplates(badState);

assertThat(issue, equalTo(
new DeprecationIssue(DeprecationIssue.Level.CRITICAL,
"component templates and index templates contain deprecated sparse_vector fields that must be removed",
"https://www.elastic.co/guide/en/elasticsearch/reference/master/migrating-8.0.html#breaking_80_search_changes",
"mappings in component template [my-template] contains deprecated sparse_vector fields: [my_sparse_vector]; " +
"mappings in index template single-type contains deprecated sparse_vector fields: " +
"[my_sparse_vector], [my_nested_sparse_vector]", false, null)
));
}
}

0 comments on commit bbe4c48

Please sign in to comment.