|
@@ -13,20 +13,51 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsAction
|
|
|
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
|
|
|
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData;
|
|
|
import org.elasticsearch.client.Client;
|
|
|
+import org.elasticsearch.index.mapper.NumberFieldMapper;
|
|
|
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
|
|
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
|
|
|
+import org.elasticsearch.xpack.core.ClientHelper;
|
|
|
import org.elasticsearch.xpack.core.dataframe.transforms.pivot.PivotConfig;
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+import java.util.stream.Stream;
|
|
|
|
|
|
-public class SchemaUtil {
|
|
|
+public final class SchemaUtil {
|
|
|
private static final Logger logger = LogManager.getLogger(SchemaUtil.class);
|
|
|
|
|
|
+ // Full collection of numeric field type strings
|
|
|
+ private static final Set<String> NUMERIC_FIELD_MAPPER_TYPES;
|
|
|
+ static {
|
|
|
+ Set<String> types = Stream.of(NumberFieldMapper.NumberType.values())
|
|
|
+ .map(NumberFieldMapper.NumberType::typeName)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ types.add("scaled_float"); // have to add manually since scaled_float is in a module
|
|
|
+ NUMERIC_FIELD_MAPPER_TYPES = types;
|
|
|
+ }
|
|
|
+
|
|
|
private SchemaUtil() {
|
|
|
}
|
|
|
|
|
|
- public static void deduceMappings(final Client client, final PivotConfig config, final String source,
|
|
|
+ public static boolean isNumericType(String type) {
|
|
|
+ return type != null && NUMERIC_FIELD_MAPPER_TYPES.contains(type);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Deduce the mappings for the destination index given the source index
|
|
|
+ *
|
|
|
+ * The Listener is alerted with a {@code Map<String, String>} that is a "field-name":"type" mapping
|
|
|
+ *
|
|
|
+ * @param client Client from which to make requests against the cluster
|
|
|
+ * @param config The PivotConfig for which to deduce destination mapping
|
|
|
+ * @param source Source index that contains the data to pivot
|
|
|
+ * @param listener Listener to alert on success or failure.
|
|
|
+ */
|
|
|
+ public static void deduceMappings(final Client client,
|
|
|
+ final PivotConfig config,
|
|
|
+ final String source,
|
|
|
final ActionListener<Map<String, String>> listener) {
|
|
|
// collects the fieldnames used as source for aggregations
|
|
|
Map<String, String> aggregationSourceFieldNames = new HashMap<>();
|
|
@@ -56,18 +87,42 @@ public class SchemaUtil {
|
|
|
allFieldNames.putAll(fieldNamesForGrouping);
|
|
|
|
|
|
getSourceFieldMappings(client, source, allFieldNames.values().toArray(new String[0]),
|
|
|
- ActionListener.wrap(sourceMappings -> {
|
|
|
- Map<String, String> targetMapping = resolveMappings(aggregationSourceFieldNames, aggregationTypes,
|
|
|
- fieldNamesForGrouping, sourceMappings);
|
|
|
-
|
|
|
- listener.onResponse(targetMapping);
|
|
|
- }, e -> {
|
|
|
- listener.onFailure(e);
|
|
|
- }));
|
|
|
+ ActionListener.wrap(
|
|
|
+ sourceMappings -> listener.onResponse(resolveMappings(aggregationSourceFieldNames,
|
|
|
+ aggregationTypes,
|
|
|
+ fieldNamesForGrouping,
|
|
|
+ sourceMappings)),
|
|
|
+ listener::onFailure));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gathers the field mappings for the "destination" index. Listener will receive an error, or a {@code Map<String, String>} of
|
|
|
+ * "field-name":"type".
|
|
|
+ *
|
|
|
+ * @param client Client used to execute the request
|
|
|
+ * @param index The index, or index pattern, from which to gather all the field mappings
|
|
|
+ * @param listener The listener to be alerted on success or failure.
|
|
|
+ */
|
|
|
+ public static void getDestinationFieldMappings(final Client client,
|
|
|
+ final String index,
|
|
|
+ final ActionListener<Map<String, String>> listener) {
|
|
|
+ GetFieldMappingsRequest fieldMappingRequest = new GetFieldMappingsRequest();
|
|
|
+ fieldMappingRequest.indices(index);
|
|
|
+ fieldMappingRequest.fields("*");
|
|
|
+ ClientHelper.executeAsyncWithOrigin(client,
|
|
|
+ ClientHelper.DATA_FRAME_ORIGIN,
|
|
|
+ GetFieldMappingsAction.INSTANCE,
|
|
|
+ fieldMappingRequest,
|
|
|
+ ActionListener.wrap(
|
|
|
+ r -> listener.onResponse(extractFieldMappings(r.mappings())),
|
|
|
+ listener::onFailure
|
|
|
+ ));
|
|
|
}
|
|
|
|
|
|
private static Map<String, String> resolveMappings(Map<String, String> aggregationSourceFieldNames,
|
|
|
- Map<String, String> aggregationTypes, Map<String, String> fieldNamesForGrouping, Map<String, String> sourceMappings) {
|
|
|
+ Map<String, String> aggregationTypes,
|
|
|
+ Map<String, String> fieldNamesForGrouping,
|
|
|
+ Map<String, String> sourceMappings) {
|
|
|
Map<String, String> targetMapping = new HashMap<>();
|
|
|
|
|
|
aggregationTypes.forEach((targetFieldName, aggregationName) -> {
|
|
@@ -107,14 +162,12 @@ public class SchemaUtil {
|
|
|
fieldMappingRequest.indices(index);
|
|
|
fieldMappingRequest.fields(fields);
|
|
|
|
|
|
- client.execute(GetFieldMappingsAction.INSTANCE, fieldMappingRequest, ActionListener.wrap(response -> {
|
|
|
- listener.onResponse(extractSourceFieldMappings(response.mappings()));
|
|
|
- }, e -> {
|
|
|
- listener.onFailure(e);
|
|
|
- }));
|
|
|
+ client.execute(GetFieldMappingsAction.INSTANCE, fieldMappingRequest, ActionListener.wrap(
|
|
|
+ response -> listener.onResponse(extractFieldMappings(response.mappings())),
|
|
|
+ listener::onFailure));
|
|
|
}
|
|
|
|
|
|
- private static Map<String, String> extractSourceFieldMappings(Map<String, Map<String, Map<String, FieldMappingMetaData>>> mappings) {
|
|
|
+ private static Map<String, String> extractFieldMappings(Map<String, Map<String, Map<String, FieldMappingMetaData>>> mappings) {
|
|
|
Map<String, String> extractedTypes = new HashMap<>();
|
|
|
|
|
|
mappings.forEach((indexName, docTypeToMapping) -> {
|