This is an automated email from the ASF dual-hosted git repository.
xiaokang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-graphar.git
The following commit(s) were added to refs/heads/main by this push:
new bb4a1d33 feat(java,info): support multi-labels in yaml (#781)
bb4a1d33 is described below
commit bb4a1d335c9f8f50a534ccf08432b101aa493ae9
Author: Xiaokang Yang <[email protected]>
AuthorDate: Mon Dec 8 20:30:12 2025 +0800
feat(java,info): support multi-labels in yaml (#781)
* add multi labels
* fix
* format
* update
* fix
* update
---
.../java/org/apache/graphar/info/VertexInfo.java | 63 +++++++-
.../graphar/info/loader/BaseGraphInfoLoader.java | 1 +
.../org/apache/graphar/info/yaml/VertexYaml.java | 4 +
.../org/apache/graphar/info/GraphInfoTest.java | 1 +
.../apache/graphar/info/TestVerificationUtils.java | 2 +
.../apache/graphar/info/VertexInfoLabelsTest.java | 178 +++++++++++++++++++++
6 files changed, 246 insertions(+), 3 deletions(-)
diff --git
a/maven-projects/info/src/main/java/org/apache/graphar/info/VertexInfo.java
b/maven-projects/info/src/main/java/org/apache/graphar/info/VertexInfo.java
index 5821216f..c6f4603d 100644
--- a/maven-projects/info/src/main/java/org/apache/graphar/info/VertexInfo.java
+++ b/maven-projects/info/src/main/java/org/apache/graphar/info/VertexInfo.java
@@ -22,6 +22,7 @@ package org.apache.graphar.info;
import java.io.Writer;
import java.net.URI;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
@@ -36,6 +37,7 @@ public class VertexInfo {
private final String type;
private final long chunkSize;
private final PropertyGroups propertyGroups;
+ private final List<String> labels;
private final URI baseUri;
private final VersionInfo version;
@@ -49,6 +51,7 @@ public class VertexInfo {
private PropertyGroups propertyGroups;
private URI baseUri;
private VersionInfo version;
+ private List<String> labels;
private List<PropertyGroup> propertyGroupsAsListTemp;
private VertexInfoBuilder() {}
@@ -87,6 +90,19 @@ public class VertexInfo {
return this;
}
+ public VertexInfoBuilder labels(List<String> labels) {
+ this.labels = labels;
+ return this;
+ }
+
+ public VertexInfoBuilder addLabel(String label) {
+ if (labels == null) {
+ labels = new ArrayList<>();
+ }
+ labels.add(label);
+ return this;
+ }
+
public VertexInfoBuilder addPropertyGroup(PropertyGroup propertyGroup)
{
if (propertyGroupsAsListTemp == null) {
propertyGroupsAsListTemp = new ArrayList<>();
@@ -109,6 +125,14 @@ public class VertexInfo {
}
public VertexInfo build() {
+ if (type == null || type.isEmpty()) {
+ throw new IllegalArgumentException("Type cannot be null or
empty");
+ }
+
+ if (labels == null) {
+ labels = Collections.emptyList();
+ }
+
if (propertyGroups == null && propertyGroupsAsListTemp != null) {
propertyGroups = new PropertyGroups(propertyGroupsAsListTemp);
} else if (propertyGroupsAsListTemp != null) {
@@ -127,6 +151,7 @@ public class VertexInfo {
if (baseUri == null) {
throw new IllegalArgumentException("Base URI cannot be null");
}
+
return new VertexInfo(this);
}
}
@@ -134,6 +159,7 @@ public class VertexInfo {
private VertexInfo(VertexInfoBuilder builder) {
this.type = builder.type;
this.chunkSize = builder.chunkSize;
+ this.labels = builder.labels;
this.propertyGroups = builder.propertyGroups;
this.baseUri = builder.baseUri;
this.version = builder.version;
@@ -145,7 +171,17 @@ public class VertexInfo {
List<PropertyGroup> propertyGroups,
String prefix,
String version) {
- this(type, chunkSize, propertyGroups, URI.create(prefix), version);
+ this(type, chunkSize, propertyGroups, Collections.emptyList(),
URI.create(prefix), version);
+ }
+
+ public VertexInfo(
+ String type,
+ long chunkSize,
+ List<PropertyGroup> propertyGroups,
+ List<String> labels,
+ String prefix,
+ String version) {
+ this(type, chunkSize, propertyGroups, labels, URI.create(prefix),
version);
}
public VertexInfo(
@@ -154,13 +190,24 @@ public class VertexInfo {
List<PropertyGroup> propertyGroups,
URI baseUri,
String version) {
- this(type, chunkSize, propertyGroups, baseUri,
VersionParser.getVersion(version));
+ this(type, chunkSize, propertyGroups, Collections.emptyList(),
baseUri, version);
}
public VertexInfo(
String type,
long chunkSize,
List<PropertyGroup> propertyGroups,
+ List<String> labels,
+ URI baseUri,
+ String version) {
+ this(type, chunkSize, propertyGroups, labels, baseUri,
VersionParser.getVersion(version));
+ }
+
+ public VertexInfo(
+ String type,
+ long chunkSize,
+ List<PropertyGroup> propertyGroups,
+ List<String> labels,
URI baseUri,
VersionInfo version) {
if (chunkSize < 0) {
@@ -169,6 +216,7 @@ public class VertexInfo {
this.type = type;
this.chunkSize = chunkSize;
this.propertyGroups = new PropertyGroups(propertyGroups);
+ this.labels = labels == null ? Collections.emptyList() :
List.copyOf(labels);
this.baseUri = baseUri;
this.version = version;
}
@@ -180,7 +228,12 @@ public class VertexInfo {
.map(
newPropertyGroups ->
new VertexInfo(
- type, chunkSize, newPropertyGroups,
baseUri, version));
+ type,
+ chunkSize,
+ newPropertyGroups,
+ labels,
+ baseUri,
+ version));
}
public int getPropertyGroupNum() {
@@ -255,6 +308,10 @@ public class VertexInfo {
return chunkSize;
}
+ public List<String> getLabels() {
+ return labels;
+ }
+
public List<PropertyGroup> getPropertyGroups() {
return propertyGroups.getPropertyGroupList();
}
diff --git
a/maven-projects/info/src/main/java/org/apache/graphar/info/loader/BaseGraphInfoLoader.java
b/maven-projects/info/src/main/java/org/apache/graphar/info/loader/BaseGraphInfoLoader.java
index 50463373..e5767b94 100644
---
a/maven-projects/info/src/main/java/org/apache/graphar/info/loader/BaseGraphInfoLoader.java
+++
b/maven-projects/info/src/main/java/org/apache/graphar/info/loader/BaseGraphInfoLoader.java
@@ -76,6 +76,7 @@ public abstract class BaseGraphInfoLoader implements
GraphInfoLoader {
vertexYaml.getProperty_groups().stream()
.map(PropertyGroupYaml::toPropertyGroup)
.collect(Collectors.toList()),
+ vertexYaml.getLabels(),
vertexYaml.getPrefix(),
vertexYaml.getVersion());
}
diff --git
a/maven-projects/info/src/main/java/org/apache/graphar/info/yaml/VertexYaml.java
b/maven-projects/info/src/main/java/org/apache/graphar/info/yaml/VertexYaml.java
index 42d5a3fc..77342324 100644
---
a/maven-projects/info/src/main/java/org/apache/graphar/info/yaml/VertexYaml.java
+++
b/maven-projects/info/src/main/java/org/apache/graphar/info/yaml/VertexYaml.java
@@ -50,6 +50,7 @@ public class VertexYaml {
vertexInfo.getPropertyGroups().stream()
.map(PropertyGroupYaml::new)
.collect(Collectors.toList());
+ this.labels = vertexInfo.getLabels();
this.prefix = vertexInfo.getPrefix();
this.version =
Optional.of(vertexInfo)
@@ -86,6 +87,9 @@ public class VertexYaml {
if (labels == null) {
return null;
}
+ // Returns the labels list, or null if the list is null or empty.
Returning null for empty
+ // lists ensures that the labels field is omitted from YAML output
when no labels are
+ // defined.
return labels.isEmpty() ? null : labels;
}
diff --git
a/maven-projects/info/src/test/java/org/apache/graphar/info/GraphInfoTest.java
b/maven-projects/info/src/test/java/org/apache/graphar/info/GraphInfoTest.java
index 77efdc6b..0ba983ab 100644
---
a/maven-projects/info/src/test/java/org/apache/graphar/info/GraphInfoTest.java
+++
b/maven-projects/info/src/test/java/org/apache/graphar/info/GraphInfoTest.java
@@ -116,6 +116,7 @@ public class GraphInfoTest {
public void testPersonVertexInfoBasics() {
VertexInfo personVertexInfo = graphInfo.getVertexInfos().get(0);
Assert.assertEquals("person", personVertexInfo.getType());
+ Assert.assertTrue(personVertexInfo.getLabels().isEmpty());
Assert.assertEquals(100, personVertexInfo.getChunkSize());
Assert.assertEquals("vertex/person/", personVertexInfo.getPrefix());
Assert.assertEquals(URI.create("vertex/person/"),
personVertexInfo.getBaseUri());
diff --git
a/maven-projects/info/src/test/java/org/apache/graphar/info/TestVerificationUtils.java
b/maven-projects/info/src/test/java/org/apache/graphar/info/TestVerificationUtils.java
index ddf66067..b9687787 100644
---
a/maven-projects/info/src/test/java/org/apache/graphar/info/TestVerificationUtils.java
+++
b/maven-projects/info/src/test/java/org/apache/graphar/info/TestVerificationUtils.java
@@ -234,6 +234,8 @@ public class TestVerificationUtils {
return false;
}
+ Assert.assertEquals("VertexInfo labels mismatch",
expected.getLabels(), actual.getLabels());
+
Assert.assertEquals("VertexInfo type mismatch", expected.getType(),
actual.getType());
Assert.assertEquals(
"VertexInfo chunk size mismatch", expected.getChunkSize(),
actual.getChunkSize());
diff --git
a/maven-projects/info/src/test/java/org/apache/graphar/info/VertexInfoLabelsTest.java
b/maven-projects/info/src/test/java/org/apache/graphar/info/VertexInfoLabelsTest.java
new file mode 100644
index 00000000..ed331b90
--- /dev/null
+++
b/maven-projects/info/src/test/java/org/apache/graphar/info/VertexInfoLabelsTest.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.graphar.info;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.graphar.info.loader.GraphInfoLoader;
+import
org.apache.graphar.info.loader.impl.LocalFileSystemStringGraphInfoLoader;
+import org.apache.graphar.info.saver.GraphInfoSaver;
+import org.apache.graphar.info.saver.impl.LocalFileSystemYamlGraphSaver;
+import org.apache.graphar.info.type.DataType;
+import org.apache.graphar.info.type.FileType;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class VertexInfoLabelsTest extends BaseFileSystemTest {
+
+ private String testSaveDirectory;
+ private GraphInfoSaver graphInfoSaver;
+ private GraphInfoLoader graphInfoLoader;
+
+ @Before
+ public void setUp() {
+ testSaveDirectory =
createCleanTestDirectory("ldbc_multi_labels_sample/");
+ graphInfoSaver = new LocalFileSystemYamlGraphSaver();
+ graphInfoLoader = new LocalFileSystemStringGraphInfoLoader();
+ }
+
+ @After
+ public void tearDown() {
+ // Test data will be preserved for debugging - cleanup happens before
next test run
+ System.out.println("Test data saved in: " + testSaveDirectory);
+ }
+
+ @Test
+ public void testVertexInfoWithLabels() throws IOException {
+ // Create property group
+ Property property = new Property("id", DataType.INT32, true, false);
+ PropertyGroup propertyGroup =
+ new PropertyGroup(Collections.singletonList(property),
FileType.PARQUET, "test/");
+
+ // Create labels
+ List<String> labels = Arrays.asList("Person", "Employee", "User");
+
+ // Create vertex info with labels
+ VertexInfo vertexInfo =
+ new VertexInfo(
+ "person",
+ 100L,
+ Collections.singletonList(propertyGroup),
+ labels,
+ "vertex/person/",
+ "gar/v1");
+
+ // Test getters
+ Assert.assertEquals("person", vertexInfo.getType());
+ Assert.assertEquals(100L, vertexInfo.getChunkSize());
+ Assert.assertEquals(labels, vertexInfo.getLabels());
+ Assert.assertEquals("vertex/person/", vertexInfo.getPrefix());
+ Assert.assertEquals("gar/v1", vertexInfo.getVersion().toString());
+
+ // Test property group related methods
+ Assert.assertEquals(1, vertexInfo.getPropertyGroupNum());
+ Assert.assertTrue(vertexInfo.hasProperty("id"));
+ Assert.assertTrue(vertexInfo.isPrimaryKey("id"));
+ Assert.assertFalse(vertexInfo.isNullableKey("id"));
+
+ // Test validation
+ Assert.assertTrue(vertexInfo.isValidated());
+
+ // Test dump
+ graphInfoSaver.save(URI.create(testSaveDirectory), vertexInfo);
+ // test load
+ VertexInfo loadedVertexInfo =
+ graphInfoLoader.loadVertexInfo(URI.create(testSaveDirectory +
"person.vertex.yml"));
+ Assert.assertTrue(TestVerificationUtils.equalsVertexInfo(vertexInfo,
loadedVertexInfo));
+ }
+
+ @Test
+ public void testVertexInfoWithoutLabels() throws IOException {
+ // Create property group
+ Property property = new Property("id", DataType.INT32, true, false);
+ PropertyGroup propertyGroup =
+ new PropertyGroup(Collections.singletonList(property),
FileType.PARQUET, "test/");
+
+ // Create vertex info without labels (using old constructor)
+ VertexInfo vertexInfo =
+ new VertexInfo(
+ "person",
+ 100L,
+ Collections.singletonList(propertyGroup),
+ "vertex/person/",
+ "gar/v1");
+
+ // Test that labels list is empty but not null
+ Assert.assertEquals("person", vertexInfo.getType());
+ Assert.assertEquals(100L, vertexInfo.getChunkSize());
+ Assert.assertNotNull(vertexInfo.getLabels());
+ Assert.assertTrue(vertexInfo.getLabels().isEmpty());
+ Assert.assertEquals("vertex/person/", vertexInfo.getPrefix());
+
+ // Test validation
+ Assert.assertTrue(vertexInfo.isValidated());
+ // Test dump
+ graphInfoSaver.save(URI.create(testSaveDirectory), vertexInfo);
+ // test load
+ VertexInfo loadedVertexInfo =
+ graphInfoLoader.loadVertexInfo(URI.create(testSaveDirectory +
"person.vertex.yml"));
+ Assert.assertTrue(TestVerificationUtils.equalsVertexInfo(vertexInfo,
loadedVertexInfo));
+ }
+
+ @Test
+ public void testVertexInfoWithEmptyLabels() throws IOException {
+ // Create property group
+ Property property = new Property("id", DataType.INT32, true, false);
+ PropertyGroup propertyGroup =
+ new PropertyGroup(Collections.singletonList(property),
FileType.PARQUET, "test/");
+
+ // Create vertex info with empty labels
+ VertexInfo vertexInfo =
+ new VertexInfo(
+ "person",
+ 100L,
+ Collections.singletonList(propertyGroup),
+ Collections.emptyList(),
+ "vertex/person/",
+ "gar/v1");
+
+ // Test that labels list is empty but not null
+ Assert.assertEquals("person", vertexInfo.getType());
+ Assert.assertEquals(100L, vertexInfo.getChunkSize());
+ Assert.assertNotNull(vertexInfo.getLabels());
+ Assert.assertTrue(vertexInfo.getLabels().isEmpty());
+ Assert.assertEquals("vertex/person/", vertexInfo.getPrefix());
+
+ // Test validation
+ Assert.assertTrue(vertexInfo.isValidated());
+ // Test dump
+ graphInfoSaver.save(URI.create(testSaveDirectory), vertexInfo);
+ // test load
+ VertexInfo loadedVertexInfo =
+ graphInfoLoader.loadVertexInfo(URI.create(testSaveDirectory +
"person.vertex.yml"));
+ Assert.assertTrue(TestVerificationUtils.equalsVertexInfo(vertexInfo,
loadedVertexInfo));
+ }
+
+ @Test
+ public void testLoadFromTestData() throws IOException {
+ URI GRAPH_PATH_URI = TestUtil.getLdbcGraphURI();
+ GraphInfo graphInfo = graphInfoLoader.loadGraphInfo(GRAPH_PATH_URI);
+ VertexInfo placeInfo = graphInfo.getVertexInfo("place");
+ VertexInfo organisationInfo = graphInfo.getVertexInfo("organisation");
+ Assert.assertEquals(List.of("city", "country", "continent"),
placeInfo.getLabels());
+ Assert.assertEquals(
+ List.of("university", "company", "public"),
organisationInfo.getLabels());
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]