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

org.securegraph.elasticsearch.ElasticSearchParentChildSearchIndex Maven / Gradle / Ivy

There is a newer version: 0.9.1
Show newest version
package org.securegraph.elasticsearch;

import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.deletebyquery.DeleteByQueryResponse;
import org.elasticsearch.action.deletebyquery.IndexDeleteByQueryResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.securegraph.*;
import org.securegraph.property.StreamingPropertyValue;
import org.securegraph.query.GraphQuery;
import org.securegraph.type.GeoPoint;
import org.securegraph.util.StreamUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class ElasticSearchParentChildSearchIndex extends ElasticSearchSearchIndexBase {
    private static final Logger LOGGER = LoggerFactory.getLogger(ElasticSearchParentChildSearchIndex.class);
    public static final String PROPERTY_TYPE = "property";

    public ElasticSearchParentChildSearchIndex(Map config) {
        super(config);
    }

    @Override
    protected void createIndex(boolean storeSourceData) throws IOException {
        super.createIndex(storeSourceData);
        XContentBuilder mapping = XContentFactory.jsonBuilder()
                .startObject()
                .startObject(PROPERTY_TYPE)
                .startObject("_parent").field("type", ELEMENT_TYPE).endObject()
                .startObject("_source").field("enabled", storeSourceData).endObject()
                .startObject("properties")
                .startObject(VISIBILITY_FIELD_NAME).field("type", "string").field("store", "true").endObject()
                .endObject()
                .endObject()
                .endObject();
        LOGGER.debug(mapping.string());
        PutMappingResponse response = getClient()
                .admin()
                .indices()
                .preparePutMapping(getIndexName())
                .setIgnoreConflicts(false)
                .setType(PROPERTY_TYPE)
                .setSource(mapping)
                .execute()
                .actionGet();
        LOGGER.debug(response.toString());
    }

    @Override
    public void removeElement(Graph graph, Element element, Authorizations authorizations) {
        deleteChildDocuments(element);
        deleteParentDocument(element);
    }

    private void deleteChildDocuments(Element element) {
        String parentId = element.getId().toString();
        DeleteByQueryResponse response = getClient()
                .prepareDeleteByQuery(getIndexName())
                .setTypes(PROPERTY_TYPE)
                .setQuery(
                        QueryBuilders.termQuery("_parent", ELEMENT_TYPE + "#" + parentId)
                )
                .execute()
                .actionGet();
        if (response.status() != RestStatus.OK) {
            throw new SecureGraphException("Could not remove child elements " + element.getId() + " (status: " + response.status() + ")");
        }
        if (LOGGER.isDebugEnabled()) {
            for (IndexDeleteByQueryResponse r : response) {
                LOGGER.debug("deleted child document " + r.toString());
            }
        }
    }

    private void deleteParentDocument(Element element) {
        String id = element.getId().toString();
        LOGGER.debug("deleting parent document " + id);
        DeleteResponse deleteResponse = getClient().delete(
                getClient()
                        .prepareDelete(getIndexName(), ELEMENT_TYPE, id)
                        .request()
        ).actionGet();
        if (!deleteResponse.isFound()) {
            throw new SecureGraphException("Could not remove element " + element.getId());
        }
    }

    @Override
    public void removeProperty(Graph graph, Element element, Property property, Authorizations authorizations) {
        String id = getChildDocId(element, property);
        DeleteResponse deleteResponse = getClient().delete(
                getClient()
                        .prepareDelete(getIndexName(), PROPERTY_TYPE, id)
                        .request()
        ).actionGet();
        if (!deleteResponse.isFound()) {
            throw new SecureGraphException("Could not remove property " + element.getId() + " " + property.toString());
        }
        LOGGER.debug("deleted property " + element.getId() + " " + property.toString());
    }

    @Override
    public void addElement(Graph graph, Element element, Authorizations authorizations) {
        addPropertiesToIndex(element.getProperties());

        try {
            try {
                addParentDocument(graph, element, authorizations);
            } catch (Exception ex) {
                throw new SecureGraphException("Could not add parent document", ex);
            }

            for (Property property : element.getProperties()) {
                try {
                    addPropertyDocument(graph, element, property, authorizations);
                } catch (Exception ex) {
                    throw new SecureGraphException("Could not add property: " + property, ex);
                }
            }

            if (isAutoflush()) {
                flush();
            }
        } catch (Exception e) {
            throw new SecureGraphException("Could not add element", e);
        }

        if (isUseEdgeBoost() && element instanceof Edge) {
            Element vOut = ((Edge) element).getVertex(Direction.OUT, authorizations);
            if (vOut != null) {
                addElement(graph, vOut, authorizations);
            }
            Element vIn = ((Edge) element).getVertex(Direction.IN, authorizations);
            if (vIn != null) {
                addElement(graph, vIn, authorizations);
            }
        }
    }

    private void addPropertyDocument(Graph graph, Element element, Property property, Authorizations authorizations) throws IOException {
        XContentBuilder jsonBuilder = buildJsonContentFromProperty(graph, element, property, authorizations);
        if (jsonBuilder == null) {
            return;
        }

        String id = getChildDocId(element, property);

        LOGGER.debug(jsonBuilder.string());
        IndexRequestBuilder builder = getClient().prepareIndex(getIndexName(), PROPERTY_TYPE, id);
        builder = builder.setParent(element.getId().toString());
        builder = builder.setSource(jsonBuilder);
        IndexResponse response = builder.execute().actionGet();
        if (response.getId() == null) {
            throw new SecureGraphException("Could not index document " + element.getId());
        }
    }

    private String getChildDocId(Element element, Property property) {
        return element.getId().toString() + "_" + property.getName() + "_" + property.getKey();
    }

    private void addParentDocument(Graph graph, Element element, Authorizations authorizations) throws IOException {
        XContentBuilder jsonBuilder;
        jsonBuilder = XContentFactory.jsonBuilder()
                .startObject();

        String id = element.getId().toString();
        if (element instanceof Vertex) {
            jsonBuilder.field(ElasticSearchSearchIndexBase.ELEMENT_TYPE_FIELD_NAME, ElasticSearchSearchIndexBase.ELEMENT_TYPE_VERTEX);
            if (isUseEdgeBoost()) {
                int inEdgeCount = ((Vertex) element).getEdgeCount(Direction.IN, authorizations);
                jsonBuilder.field(ElasticSearchSearchIndexBase.IN_EDGE_COUNT_FIELD_NAME, inEdgeCount);
                int outEdgeCount = ((Vertex) element).getEdgeCount(Direction.OUT, authorizations);
                jsonBuilder.field(ElasticSearchSearchIndexBase.OUT_EDGE_COUNT_FIELD_NAME, outEdgeCount);
            }
        } else if (element instanceof Edge) {
            jsonBuilder.field(ElasticSearchSearchIndexBase.ELEMENT_TYPE_FIELD_NAME, ElasticSearchSearchIndexBase.ELEMENT_TYPE_EDGE);
        } else {
            throw new SecureGraphException("Unexpected element type " + element.getClass().getName());
        }

        jsonBuilder.field(VISIBILITY_FIELD_NAME, element.getVisibility().getVisibilityString());

        IndexResponse response = getClient()
                .prepareIndex(getIndexName(), ELEMENT_TYPE, id)
                .setSource(jsonBuilder.endObject())
                .execute()
                .actionGet();
        if (response.getId() == null) {
            throw new SecureGraphException("Could not index document " + element.getId());
        }
    }

    private XContentBuilder buildJsonContentFromProperty(Graph graph, Element element, Property property, Authorizations authorizations) throws IOException {
        XContentBuilder jsonBuilder;
        jsonBuilder = XContentFactory.jsonBuilder()
                .startObject();

        Object propertyValue = property.getValue();
        if (propertyValue != null && shouldIgnoreType(propertyValue.getClass())) {
            return null;
        } else if (propertyValue instanceof GeoPoint) {
            GeoPoint geoPoint = (GeoPoint) propertyValue;
            Map propertyValueMap = new HashMap();
            propertyValueMap.put("lat", geoPoint.getLatitude());
            propertyValueMap.put("lon", geoPoint.getLongitude());
            propertyValue = propertyValueMap;
        } else if (propertyValue instanceof StreamingPropertyValue) {
            StreamingPropertyValue streamingPropertyValue = (StreamingPropertyValue) propertyValue;
            if (!streamingPropertyValue.isSearchIndex()) {
                return null;
            }
            Class valueType = streamingPropertyValue.getValueType();
            if (valueType == String.class) {
                InputStream in = streamingPropertyValue.getInputStream();
                propertyValue = StreamUtils.toString(in);
            } else {
                throw new SecureGraphException("Unhandled StreamingPropertyValue type: " + valueType.getName());
            }
        } else if (propertyValue instanceof String) {
            PropertyDefinition propertyDefinition = getPropertyDefinitions().get(property.getName());
            if (propertyDefinition == null || propertyDefinition.getTextIndexHints().contains(TextIndexHint.EXACT_MATCH)) {
                jsonBuilder.field(property.getName() + ElasticSearchSearchIndexBase.EXACT_MATCH_PROPERTY_NAME_SUFFIX, propertyValue);
            }
            if (propertyDefinition == null || propertyDefinition.getTextIndexHints().contains(TextIndexHint.FULL_TEXT)) {
                jsonBuilder.field(property.getName(), propertyValue);
            }
        }

        if (propertyValue instanceof DateOnly) {
            propertyValue = ((DateOnly) propertyValue).getDate();
        }

        jsonBuilder.field(property.getName(), propertyValue);
        jsonBuilder.field(VISIBILITY_FIELD_NAME, property.getVisibility().getVisibilityString());

        return jsonBuilder;
    }

    @Override
    public GraphQuery queryGraph(Graph graph, String queryString, Authorizations authorizations) {
        return new ElasticSearchParentChildGraphQuery(getClient(), getIndexName(), graph, queryString, getPropertyDefinitions(), getInEdgeBoost(), getOutEdgeBoost(), authorizations);
    }

    @Override
    protected void addPropertyToIndex(String propertyName, Class dataType, boolean analyzed, Double boost) throws IOException {
        if (getPropertyDefinitions().get(propertyName) != null) {
            return;
        }

        if (shouldIgnoreType(dataType)) {
            return;
        }

        XContentBuilder mapping = XContentFactory.jsonBuilder()
                .startObject()
                .startObject(PROPERTY_TYPE)
                .startObject("_parent").field("type", ELEMENT_TYPE).endObject()
                .startObject("properties")
                .startObject(propertyName);

        addTypeToMapping(mapping, propertyName, dataType, analyzed, boost);

        mapping
                .endObject()
                .endObject()
                .endObject()
                .endObject();

        PutMappingResponse response = getClient()
                .admin()
                .indices()
                .preparePutMapping(getIndexName())
                .setIgnoreConflicts(false)
                .setType(PROPERTY_TYPE)
                .setSource(mapping)
                .execute()
                .actionGet();
        LOGGER.debug(response.toString());

        getPropertyDefinitions().put(propertyName, new PropertyDefinition(propertyName, dataType, TextIndexHint.ALL));
    }

    @Override
    public boolean isEdgeBoostSupported() {
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy