package org.vertexium; import org.vertexium.id.IdGenerator; import org.vertexium.mutation.ElementMutation; import org.vertexium.mutation.ExistingElementMutation; import org.vertexium.mutation.ExtendedDataMutation; import org.vertexium.query.GraphQuery; import org.vertexium.query.MultiVertexQuery; import org.vertexium.query.SimilarToGraphQuery; import org.vertexium.search.IndexHint; import org.vertexium.search.SearchIndex; import org.vertexium.search.SearchIndexWithVertexPropertyCountByValue; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Map; public abstract class GraphBaseWithSearchIndex extends GraphBase implements Graph, GraphWithSearchIndex { public static final String METADATA_ID_GENERATOR_CLASSNAME = "idGenerator.classname"; private final GraphConfiguration configuration; private final IdGenerator idGenerator; private final EnumSet<FetchHint> defaultFetchHints; private SearchIndex searchIndex; private boolean foundIdGeneratorClassnameInMetadata; protected GraphBaseWithSearchIndex(GraphConfiguration configuration) { super(configuration.isStrictTyping()); this.configuration = configuration; this.searchIndex = configuration.createSearchIndex(this); this.idGenerator = configuration.createIdGenerator(this); this.defaultFetchHints = FetchHint.parse(configuration.getString(GraphConfiguration.DEFAULT_FETCH_HINTS, GraphConfiguration.DEFAULT_DEFAULT_FETCH_HINTS)); } protected GraphBaseWithSearchIndex(GraphConfiguration configuration, IdGenerator idGenerator, SearchIndex searchIndex) { super(configuration.isStrictTyping()); this.configuration = configuration; this.searchIndex = searchIndex; this.idGenerator = idGenerator; this.defaultFetchHints = FetchHint.parse(configuration.getString(GraphConfiguration.DEFAULT_FETCH_HINTS, GraphConfiguration.DEFAULT_DEFAULT_FETCH_HINTS)); } protected void setup() { setupGraphMetadata(); } protected void setupGraphMetadata() { foundIdGeneratorClassnameInMetadata = false; for (GraphMetadataEntry graphMetadataEntry : getMetadata()) { setupGraphMetadata(graphMetadataEntry); } if (!foundIdGeneratorClassnameInMetadata) { setMetadata(METADATA_ID_GENERATOR_CLASSNAME, this.idGenerator.getClass().getName()); } } protected void setupGraphMetadata(GraphMetadataEntry graphMetadataEntry) { if (graphMetadataEntry.getKey().startsWith(METADATA_DEFINE_PROPERTY_PREFIX)) { if (graphMetadataEntry.getValue() instanceof PropertyDefinition) { addToPropertyDefinitionCache((PropertyDefinition) graphMetadataEntry.getValue()); } else { throw new VertexiumException("Invalid property definition metadata: " + graphMetadataEntry.getKey() + " expected " + PropertyDefinition.class.getName() + " found " + graphMetadataEntry.getValue().getClass().getName()); } } else if (graphMetadataEntry.getKey().equals(METADATA_ID_GENERATOR_CLASSNAME)) { if (graphMetadataEntry.getValue() instanceof String) { String idGeneratorClassname = (String) graphMetadataEntry.getValue(); if (idGeneratorClassname.equals(idGenerator.getClass().getName())) { foundIdGeneratorClassnameInMetadata = true; } } else { throw new VertexiumException("Invalid " + METADATA_ID_GENERATOR_CLASSNAME + " expected String found " + graphMetadataEntry.getValue().getClass().getName()); } } } @Override public GraphQuery query(Authorizations authorizations) { return getSearchIndex().queryGraph(this, null, authorizations); } @Override public GraphQuery query(String queryString, Authorizations authorizations) { return getSearchIndex().queryGraph(this, queryString, authorizations); } @Override public MultiVertexQuery query(String[] vertexIds, String queryString, Authorizations authorizations) { return getSearchIndex().queryGraph(this, vertexIds, queryString, authorizations); } @Override public MultiVertexQuery query(String[] vertexIds, Authorizations authorizations) { return getSearchIndex().queryGraph(this, vertexIds, null, authorizations); } @Override public boolean isQuerySimilarToTextSupported() { return getSearchIndex().isQuerySimilarToTextSupported(); } @Override public SimilarToGraphQuery querySimilarTo(String[] fields, String text, Authorizations authorizations) { return getSearchIndex().querySimilarTo(this, fields, text, authorizations); } public IdGenerator getIdGenerator() { return idGenerator; } public GraphConfiguration getConfiguration() { return configuration; } @Override public SearchIndex getSearchIndex() { return searchIndex; } @Override public void reindex(Authorizations authorizations) { reindexVertices(authorizations); reindexEdges(authorizations); } protected void reindexVertices(Authorizations authorizations) { this.searchIndex.addElements(this, getVertices(authorizations), authorizations); } private void reindexEdges(Authorizations authorizations) { this.searchIndex.addElements(this, getEdges(authorizations), authorizations); } @Override public void flush() { if (getSearchIndex() != null) { this.searchIndex.flush(this); } } @Override public void shutdown() { flush(); if (getSearchIndex() != null) { this.searchIndex.shutdown(); this.searchIndex = null; } } @Override public abstract void drop(); @Override public boolean isFieldBoostSupported() { return getSearchIndex().isFieldBoostSupported(); } @Override public SearchIndexSecurityGranularity getSearchIndexSecurityGranularity() { return getSearchIndex().getSearchIndexSecurityGranularity(); } @Override public Map<Object, Long> getVertexPropertyCountByValue(String propertyName, Authorizations authorizations) { if (getSearchIndex() instanceof SearchIndexWithVertexPropertyCountByValue) { return ((SearchIndexWithVertexPropertyCountByValue) getSearchIndex()).getVertexPropertyCountByValue(this, propertyName, authorizations); } return super.getVertexPropertyCountByValue(propertyName, authorizations); } @Override public Iterable<Element> saveElementMutations(Iterable<ElementMutation> mutations, Authorizations authorizations) { List<Element> elements = new ArrayList<>(); List<Element> elementsToAddToIndex = new ArrayList<>(); List<ElementAndIterableExtendedDataMutation> extendedDataToIndex = new ArrayList<>(); for (ElementMutation m : mutations) { if (m instanceof ExistingElementMutation && !m.hasChanges()) { elements.add(((ExistingElementMutation) m).getElement()); continue; } IndexHint indexHint = m.getIndexHint(); m.setIndexHint(IndexHint.DO_NOT_INDEX); Element element = m.save(authorizations); elements.add(element); if (indexHint == IndexHint.INDEX) { elementsToAddToIndex.add(element); //noinspection unchecked extendedDataToIndex.add(new ElementAndIterableExtendedDataMutation(element, m.getExtendedData())); } } getSearchIndex().addElements(this, elementsToAddToIndex, authorizations); for (ElementAndIterableExtendedDataMutation ed : extendedDataToIndex) { getSearchIndex().addElementExtendedData(this, ed.element, ed.extendedData, authorizations); } return elements; } private static class ElementAndIterableExtendedDataMutation { public final Element element; public final Iterable<ExtendedDataMutation> extendedData; public ElementAndIterableExtendedDataMutation(Element element, Iterable<ExtendedDataMutation> extendedData) { this.element = element; this.extendedData = extendedData; } } @Override public abstract VertexBuilder prepareVertex(String vertexId, Long timestamp, Visibility visibility); @Override public abstract Iterable<Vertex> getVertices(EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations); @Override public abstract EdgeBuilder prepareEdge(String edgeId, Vertex outVertex, Vertex inVertex, String label, Long timestamp, Visibility visibility); @Override public abstract EdgeBuilderByVertexId prepareEdge(String edgeId, String outVertexId, String inVertexId, String label, Long timestamp, Visibility visibility); @Override public abstract void softDeleteVertex(Vertex vertex, Long timestamp, Authorizations authorizations); @Override public abstract void softDeleteEdge(Edge edge, Long timestamp, Authorizations authorizations); @Override public abstract Iterable<Edge> getEdges(EnumSet<FetchHint> fetchHints, Long endTime, Authorizations authorizations); @Override protected abstract GraphMetadataStore getGraphMetadataStore(); @Override public abstract void deleteVertex(Vertex vertex, Authorizations authorizations); @Override public abstract void deleteEdge(Edge edge, Authorizations authorizations); @Override public abstract boolean isVisibilityValid(Visibility visibility, Authorizations authorizations); @Override public abstract void truncate(); @Override public abstract void markVertexHidden(Vertex vertex, Visibility visibility, Authorizations authorizations); @Override public abstract void markVertexVisible(Vertex vertex, Visibility visibility, Authorizations authorizations); @Override public abstract void markEdgeHidden(Edge edge, Visibility visibility, Authorizations authorizations); @Override public abstract void markEdgeVisible(Edge edge, Visibility visibility, Authorizations authorizations); @Override public abstract Authorizations createAuthorizations(String... auths); @Override public EnumSet<FetchHint> getDefaultFetchHints() { return defaultFetchHints; } }