All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.pukkaone.odata.elasticsearch2.provider.IndexToCsdlSchemaMapper Maven / Gradle / Ivy

The newest version!
package com.github.pukkaone.odata.elasticsearch2.provider;

import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.provider.CsdlComplexType;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.index.mapper.core.BinaryFieldMapper;
import org.elasticsearch.index.mapper.core.BooleanFieldMapper;
import org.elasticsearch.index.mapper.core.ByteFieldMapper;
import org.elasticsearch.index.mapper.core.DateFieldMapper;
import org.elasticsearch.index.mapper.core.DoubleFieldMapper;
import org.elasticsearch.index.mapper.core.FloatFieldMapper;
import org.elasticsearch.index.mapper.core.IntegerFieldMapper;
import org.elasticsearch.index.mapper.core.LongFieldMapper;
import org.elasticsearch.index.mapper.core.ShortFieldMapper;
import org.elasticsearch.index.mapper.core.StringFieldMapper;
import org.elasticsearch.index.mapper.geo.GeoPointFieldMapper;
import org.elasticsearch.index.mapper.geo.GeoShapeFieldMapper;

/**
 * Converts Elasticsearch index to CSDL Schema.
 */
@Slf4j
public class IndexToCsdlSchemaMapper {

  private static final String ID_PROPERTY_NAME = "_id";

  private CsdlSchema schema;
  private Map nameToEntityTypeMap = new LinkedHashMap<>();
  private Map nameToComplexTypeMap = new LinkedHashMap<>();

  private static final Map TO_PRIMITIVE_TYPE_MAP =
      ImmutableMap.builder()
          .put(BinaryFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Binary)
          .put(BooleanFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Boolean)
          .put(ByteFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Byte)
          .put(DateFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.DateTimeOffset)
          .put(DoubleFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Double)
          .put(FloatFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Single)
          .put(GeoPointFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.GeographyPoint)
          .put(GeoShapeFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.GeographyPolygon)
          .put(IntegerFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Int32)
          .put(LongFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Int64)
          .put(ShortFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.Int16)
          .put(StringFieldMapper.CONTENT_TYPE, EdmPrimitiveTypeKind.String)
          .build();

  private FullQualifiedName toPrimitiveType(String elasticsearchType) {
    EdmPrimitiveTypeKind type = TO_PRIMITIVE_TYPE_MAP.get(elasticsearchType);
    if (type == null) {
      log.warn("Elasticsearch type {} translated to OData String type", elasticsearchType);
      type = EdmPrimitiveTypeKind.String;
    }

    return type.getFullQualifiedName();
  }

  private FullQualifiedName toComplexType(
      String propertyName, Map nameToAttributeMap) {

    List properties = toProperties(nameToAttributeMap);

    CsdlComplexType complexType = new CsdlComplexType()
        .setName(propertyName)
        .setProperties(properties);

    FullQualifiedName complexTypeFqn =
        new FullQualifiedName(schema.getNamespace(), complexType.getName());
    nameToComplexTypeMap.put(complexTypeFqn, complexType);
    return complexTypeFqn;
  }

  private FullQualifiedName toPropertyType(
      String propertyName, Map nameToAttributeMap) {

    String elasticsearchType = (String) nameToAttributeMap.getOrDefault(
        "type", "object");
    if ("nested".equals(elasticsearchType) || "object".equals(elasticsearchType)) {
      return toComplexType(propertyName, nameToAttributeMap);
    }

    return toPrimitiveType(elasticsearchType);
  }

  @SuppressWarnings("unchecked")
  private CsdlProperty toProperty(String propertyName, Object propertySchema) {
    Map nameToAttributeMap = (Map) propertySchema;

    String elasticsearchType = (String) nameToAttributeMap.get("type");
    boolean isCollection = "nested".equals(elasticsearchType);

    FullQualifiedName type = toPropertyType(propertyName, nameToAttributeMap);
    return new CsdlProperty()
        .setCollection(isCollection)
        .setName(propertyName)
        .setType(type);
  }

  @SuppressWarnings("unchecked")
  private List toProperties(Map sourceSchema) {
    Map sourceProperties = (Map) sourceSchema.get("properties");

    List properties = new ArrayList<>();
    sourceProperties.forEach((propertyName, propertySchema) ->
      properties.add(toProperty(propertyName, propertySchema))
    );

    return properties;
  }

  private List toProperties(MappingMetaData mappingMetaData) {
    try {
      return toProperties(mappingMetaData.getSourceAsMap());
    } catch (IOException e) {
      throw new IllegalStateException("getSourceAsMap failed", e);
    }
  }

  private CsdlEntityType toEntityType(MappingMetaData mappingMetaData) {
    List properties = toProperties(mappingMetaData);

    properties.add(
        new CsdlProperty()
            .setName(ID_PROPERTY_NAME)
            .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName())
            .setNullable(false));

    return new CsdlEntityType()
        .setName(mappingMetaData.type())
        .setKey(Collections.singletonList(new CsdlPropertyRef().setName(ID_PROPERTY_NAME)))
        .setProperties(properties);
  }

  private CsdlEntitySet toEntitySet(MappingMetaData mappingMetaData) {
    CsdlEntityType entityType = toEntityType(mappingMetaData);

    FullQualifiedName entityTypeFqn = new FullQualifiedName(
        schema.getNamespace(), entityType.getName());
    nameToEntityTypeMap.put(entityTypeFqn, entityType);

    return new CsdlEntitySet()
        .setName(entityType.getName())
        .setType(entityTypeFqn);
  }

  private List toEntitySets(IndexMetaData indexMetaData) {
    return Streams.stream(indexMetaData.getMappings())
        .map(cursor -> toEntitySet(cursor.value))
        .collect(Collectors.toList());
  }

  private CsdlEntityContainer toEntityContainer(String indexName, IndexMetaData indexMetaData) {
    return new CsdlEntityContainer()
        .setName(indexName)
        .setEntitySets(toEntitySets(indexMetaData));
  }

  /**
   * Converts Elasticsearch index to CSDL Schema.
   *
   * @param indexName
   *     Elasticsearch index name
   * @param indexMetaData
   *     Elasticsearch index metadata
   * @return schema
   */
  public CsdlSchema toSchema(String indexName, IndexMetaData indexMetaData) {

    schema = new CsdlSchema()
        .setNamespace(indexName);
    return schema.setEntityContainer(toEntityContainer(indexName, indexMetaData))
        .setEntityTypes(new ArrayList<>(nameToEntityTypeMap.values()))
        .setComplexTypes(new ArrayList<>(nameToComplexTypeMap.values()));
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy