diff --git a/janusgraph-backend-testutils/src/main/java/org/janusgraph/graphdb/JanusGraphIndexTest.java b/janusgraph-backend-testutils/src/main/java/org/janusgraph/graphdb/JanusGraphIndexTest.java index 146d7aa920..19c897ea39 100644 --- a/janusgraph-backend-testutils/src/main/java/org/janusgraph/graphdb/JanusGraphIndexTest.java +++ b/janusgraph-backend-testutils/src/main/java/org/janusgraph/graphdb/JanusGraphIndexTest.java @@ -54,6 +54,7 @@ import org.janusgraph.core.attribute.Geoshape; import org.janusgraph.core.attribute.Text; import org.janusgraph.core.log.TransactionRecovery; +import org.janusgraph.core.schema.CompositeIndexInfo; import org.janusgraph.core.schema.JanusGraphIndex; import org.janusgraph.core.schema.JanusGraphManagement; import org.janusgraph.core.schema.Mapping; @@ -97,7 +98,6 @@ import org.janusgraph.graphdb.tinkerpop.optimize.step.JanusGraphStep; import org.janusgraph.graphdb.tinkerpop.optimize.strategy.JanusGraphMixedIndexCountStrategy; import org.janusgraph.graphdb.transaction.StandardJanusGraphTx; -import org.janusgraph.graphdb.types.CompositeIndexType; import org.janusgraph.graphdb.types.IndexField; import org.janusgraph.graphdb.types.MixedIndexType; import org.janusgraph.graphdb.types.ParameterType; @@ -162,7 +162,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - /** * @author Matthias Broecheler (me@matthiasb.com) */ @@ -4357,29 +4356,82 @@ public void testGetIndexInfo() throws DecoderException { mgmt.makeVertexLabel("cat").make(); - makeKey("id", Integer.class); + final PropertyKey idKey = makeKey("id", Integer.class); final PropertyKey nameKey = makeKey("name", String.class); + final PropertyKey metaKey = makeKey("meta", Object.class); + + String searchByNameIndex = "searchByName"; + mgmt.buildIndex(searchByNameIndex, Vertex.class) + .addKey(nameKey) + .buildCompositeIndex(); - String indexName = "searchByName"; - mgmt.buildIndex(indexName, Vertex.class) + String searchByMetaIndex = "searchByMeta"; + mgmt.buildIndex(searchByMetaIndex, Vertex.class) .addKey(nameKey) + .addKey(metaKey) .buildCompositeIndex(); + + String inlinePropIndex = "inlineProp"; + mgmt.buildIndex(inlinePropIndex, Vertex.class) + .addKey(nameKey) + .addKey(metaKey) + .addInlinePropertyKey(idKey) + .buildCompositeIndex(); + mgmt.commit(); mgmt = graph.openManagement(); + //Read index with single property Map fieldValues = new HashMap<>(); fieldValues.put("name", "someName"); - String hexString = mgmt.getIndexKey(indexName, fieldValues); - CompositeIndexType indexType = mgmt.getIndexInfo(hexString); + String hexString = mgmt.getIndexKey(searchByNameIndex, fieldValues); + CompositeIndexInfo indexInfo = mgmt.getIndexInfo(hexString); IndexField[] indexFields = new IndexField[1]; indexFields[0] = IndexField.of(nameKey); - assertEquals(indexName, indexType.getName()); - assertEquals(1, indexType.getFieldKeys().length); - assertEquals(nameKey, indexType.getFieldKeys()[0].getFieldKey()); - assertEquals(0, indexType.getInlineFieldKeys().length); + assertEquals(searchByNameIndex, indexInfo.getIndexName()); + assertEquals(1, indexInfo.getCompositeIndexType().getFieldKeys().length); + assertEquals("someName", indexInfo.getValues().get(nameKey)); + assertEquals(0, indexInfo.getCompositeIndexType().getInlineFieldKeys().length); + + //Read index with multi properties + fieldValues = new HashMap<>(); + fieldValues.put("name", "name1"); + fieldValues.put("meta", "hello"); + + hexString = mgmt.getIndexKey(searchByMetaIndex, fieldValues); + indexInfo = mgmt.getIndexInfo(hexString); + + indexFields = new IndexField[2]; + indexFields[0] = IndexField.of(nameKey); + indexFields[1] = IndexField.of(metaKey); + + assertEquals(searchByMetaIndex, indexInfo.getIndexName()); + assertEquals(2, indexInfo.getCompositeIndexType().getFieldKeys().length); + assertEquals("name1", indexInfo.getValues().get(nameKey)); + assertEquals("hello", indexInfo.getValues().get(metaKey)); + assertEquals(0, indexInfo.getCompositeIndexType().getInlineFieldKeys().length); + + //Read index with inline properties + fieldValues = new HashMap<>(); + fieldValues.put("name", "name2"); + fieldValues.put("meta", "bye"); + + hexString = mgmt.getIndexKey(inlinePropIndex, fieldValues); + indexInfo = mgmt.getIndexInfo(hexString); + + indexFields = new IndexField[2]; + indexFields[0] = IndexField.of(nameKey); + indexFields[1] = IndexField.of(metaKey); + + assertEquals(inlinePropIndex, indexInfo.getIndexName()); + assertEquals(2, indexInfo.getCompositeIndexType().getFieldKeys().length); + assertEquals("name2", indexInfo.getValues().get(nameKey)); + assertEquals("bye", indexInfo.getValues().get(metaKey)); + assertEquals(1, indexInfo.getCompositeIndexType().getInlineFieldKeys().length); + assertEquals("id", indexInfo.getCompositeIndexType().getInlineFieldKeys()[0]); } } diff --git a/janusgraph-core/src/main/java/org/janusgraph/core/schema/CompositeIndexInfo.java b/janusgraph-core/src/main/java/org/janusgraph/core/schema/CompositeIndexInfo.java new file mode 100644 index 0000000000..96d46c453c --- /dev/null +++ b/janusgraph-core/src/main/java/org/janusgraph/core/schema/CompositeIndexInfo.java @@ -0,0 +1,52 @@ +// Copyright 2025 JanusGraph Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.janusgraph.core.schema; + +import org.janusgraph.core.PropertyKey; +import org.janusgraph.graphdb.types.CompositeIndexType; + +import java.util.HashMap; +import java.util.Map; + +public class CompositeIndexInfo { + final CompositeIndexType compositeIndexType; + final Object[] indexFieldValues; + + final Map indexValues; + + public CompositeIndexInfo(CompositeIndexType compositeIndexType, Object[] indexFieldValues) { + this.compositeIndexType = compositeIndexType; + this.indexFieldValues = indexFieldValues; + + this.indexValues = new HashMap<>(); + for (int i = 0; i < compositeIndexType.getFieldKeys().length; i++) { + PropertyKey p = compositeIndexType.getFieldKeys()[i].getFieldKey(); + Object v = indexFieldValues[i]; + this.indexValues.put(p, v); + } + } + + public CompositeIndexType getCompositeIndexType() { + return compositeIndexType; + } + + public String getIndexName() { + return compositeIndexType.getName(); + } + + public Map getValues() { + return indexValues; + } +} diff --git a/janusgraph-core/src/main/java/org/janusgraph/core/schema/JanusGraphManagement.java b/janusgraph-core/src/main/java/org/janusgraph/core/schema/JanusGraphManagement.java index 46040c0e5c..2e9998fa95 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/core/schema/JanusGraphManagement.java +++ b/janusgraph-core/src/main/java/org/janusgraph/core/schema/JanusGraphManagement.java @@ -24,7 +24,6 @@ import org.janusgraph.core.RelationType; import org.janusgraph.core.VertexLabel; import org.janusgraph.diskstorage.keycolumnvalue.scan.ScanJobFuture; -import org.janusgraph.graphdb.types.CompositeIndexType; import java.time.Duration; import java.util.List; @@ -500,5 +499,5 @@ interface IndexBuilder { * @param hexString * @return composite index info */ - CompositeIndexType getIndexInfo(String hexString) throws DecoderException; + CompositeIndexInfo getIndexInfo(String hexString) throws DecoderException; } diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/IndexSerializer.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/IndexSerializer.java index 4538c9760d..9d115b212d 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/IndexSerializer.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/IndexSerializer.java @@ -26,6 +26,7 @@ import org.janusgraph.core.PropertyKey; import org.janusgraph.core.SchemaViolationException; import org.janusgraph.core.attribute.Geoshape; +import org.janusgraph.core.schema.CompositeIndexInfo; import org.janusgraph.core.schema.Parameter; import org.janusgraph.core.schema.SchemaStatus; import org.janusgraph.diskstorage.BackendException; @@ -525,6 +526,10 @@ public long getIndexIdFromKey(StaticBuffer key) { return IndexRecordUtil.getIndexIdFromKey(key, hashKeys, hashLength); } + public CompositeIndexInfo getIndexInfoFromKey(StaticBuffer key, Function compositeIndexTypeFunction) { + return IndexRecordUtil.getIndexInfoFromKey(serializer, compositeIndexTypeFunction, key, hashKeys, hashLength); + } + public StaticBuffer getIndexKey(CompositeIndexType index, Map fieldValues) { return IndexRecordUtil.getIndexKey(index, fieldValues, serializer, hashKeys, hashLength); } diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/management/ManagementSystem.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/management/ManagementSystem.java index 207aa88650..fa92a3a4bd 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/management/ManagementSystem.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/management/ManagementSystem.java @@ -37,6 +37,7 @@ import org.janusgraph.core.PropertyKey; import org.janusgraph.core.RelationType; import org.janusgraph.core.VertexLabel; +import org.janusgraph.core.schema.CompositeIndexInfo; import org.janusgraph.core.schema.ConsistencyModifier; import org.janusgraph.core.schema.EdgeLabelMaker; import org.janusgraph.core.schema.Index; @@ -566,7 +567,7 @@ public String getIndexKey(String indexName, Map fieldValues) { } @Override - public CompositeIndexType getIndexInfo(String hexString) throws DecoderException { + public CompositeIndexInfo getIndexInfo(String hexString) throws DecoderException { StaticArrayBuffer indexKey = StaticArrayBuffer.of(Hex.decodeHex(hexString)); return transaction.getCompositeIndexInfo(indexKey); } diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/util/IndexRecordUtil.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/util/IndexRecordUtil.java index f5ac5d7edb..7c9d7dc3ed 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/util/IndexRecordUtil.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/database/util/IndexRecordUtil.java @@ -14,6 +14,7 @@ package org.janusgraph.graphdb.database.util; +import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; @@ -27,6 +28,7 @@ import org.janusgraph.core.JanusGraphVertex; import org.janusgraph.core.JanusGraphVertexProperty; import org.janusgraph.core.PropertyKey; +import org.janusgraph.core.schema.CompositeIndexInfo; import org.janusgraph.core.schema.SchemaStatus; import org.janusgraph.diskstorage.Entry; import org.janusgraph.diskstorage.ReadBuffer; @@ -367,8 +369,36 @@ public static StaticBuffer getIndexKey(CompositeIndexType index, Object[] values } public static long getIndexIdFromKey(StaticBuffer key, boolean hashKeys, HashingUtil.HashLength hashLength) { - if (hashKeys) key = HashingUtil.getKey(hashLength,key); - return VariableLong.readPositive(key.asReadBuffer()); + ReadBuffer readBuffer = getIndexKeyReadBuffer(key, hashKeys, hashLength); + return VariableLong.readPositive(readBuffer); + } + + public static CompositeIndexInfo getIndexInfoFromKey(Serializer serializer, + Function compositeIndexTypeFunction, + StaticBuffer key, + boolean hashKeys, + HashingUtil.HashLength hashLength) { + + ReadBuffer readBuffer = getIndexKeyReadBuffer(key, hashKeys, hashLength); + long indexId = VariableLong.readPositive(readBuffer);//read index id + CompositeIndexType compositeIndexType = compositeIndexTypeFunction.apply(indexId); + IndexField[] fieldKeys = compositeIndexType.getFieldKeys(); + Object[] values = new Object[fieldKeys.length]; + for (int i = 0; i < fieldKeys.length; i++) { + IndexField f = fieldKeys[i]; + if (InternalAttributeUtil.hasGenericDataType(f.getFieldKey())) { + values[i] = serializer.readClassAndObject(readBuffer); + } else { + values[i] = serializer.readObjectNotNull(readBuffer, f.getFieldKey().dataType()); + } + + } + return new CompositeIndexInfo(compositeIndexType, values); + } + + private static ReadBuffer getIndexKeyReadBuffer(StaticBuffer key, boolean hashKeys, HashingUtil.HashLength hashLength) { + if (hashKeys) key = HashingUtil.getKey(hashLength, key); + return key.asReadBuffer(); } public static IndexUpdate getCompositeIndexUpdate(CompositeIndexType index, IndexMutationType indexMutationType, IndexRecordEntry[] record, diff --git a/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardJanusGraphTx.java b/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardJanusGraphTx.java index ae03100c90..499c21be7a 100644 --- a/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardJanusGraphTx.java +++ b/janusgraph-core/src/main/java/org/janusgraph/graphdb/transaction/StandardJanusGraphTx.java @@ -40,6 +40,7 @@ import org.janusgraph.core.SchemaViolationException; import org.janusgraph.core.VertexLabel; import org.janusgraph.core.attribute.Cmp; +import org.janusgraph.core.schema.CompositeIndexInfo; import org.janusgraph.core.schema.ConsistencyModifier; import org.janusgraph.core.schema.EdgeLabelMaker; import org.janusgraph.core.schema.JanusGraphSchemaElement; @@ -1258,19 +1259,24 @@ public StaticBuffer getCompositeIndexKey(String indexName, Map f } } - public CompositeIndexType getCompositeIndexInfo(StaticArrayBuffer indexKey) { - long schemaVertexId = indexSerializer.getIndexIdFromKey(indexKey); - InternalVertex typeVertex = vertexCache.get(schemaVertexId, existingVertexRetriever); + public CompositeIndexInfo getCompositeIndexInfo(StaticArrayBuffer indexKey) { - Preconditions.checkNotNull(typeVertex, "Index with key [" + indexKey + "] was not found"); - JanusGraphSchemaVertex schemaVertex = (JanusGraphSchemaVertex) typeVertex; + com.google.common.base.Function compositeIndexTypeFunction = input -> { + long schemaVertexId = indexSerializer.getIndexIdFromKey(indexKey); + InternalVertex typeVertex = vertexCache.get(schemaVertexId, existingVertexRetriever); - IndexType indexType = schemaVertex.asIndexType(); - if (indexType instanceof CompositeIndexType) { - return (CompositeIndexType) indexType; - } else { - throw new IllegalArgumentException("Index with key [" + indexKey + "] is not a composite index"); - } + Preconditions.checkNotNull(typeVertex, "Index with key [" + indexKey + "] was not found"); + JanusGraphSchemaVertex schemaVertex = (JanusGraphSchemaVertex) typeVertex; + + IndexType indexType = schemaVertex.asIndexType(); + if (indexType instanceof CompositeIndexType) { + return (CompositeIndexType) indexType; + } else { + throw new IllegalArgumentException("Index with key [" + indexKey + "] is not a composite index"); + } + }; + + return indexSerializer.getIndexInfoFromKey(indexKey, compositeIndexTypeFunction); } @Override