Skip to content

Commit b636712

Browse files
hutiefang76hutiefang
andauthored
refactor(computer): support new edgeid format in 1.7 (apache#349)
* fix: complete huge client compatibility registration --------- Co-authored-by: hutiefang <hutiefang@qq.com>
1 parent 60bb1b6 commit b636712

11 files changed

Lines changed: 273 additions & 14 deletions

File tree

.github/workflows/computer-ci.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ jobs:
2222
TRAVIS_DIR: computer-dist/src/assembly/travis
2323
BSP_ETCD_URL: http://localhost:2579
2424
KUBERNETES_VERSION: 1.20.1
25-
# TODO: adapt the HugeGraph Server/Loader version to 1.5.0 (EdgeID has 5 parts now)
26-
# NOTE: Remember to adaptor/update the version before new release
27-
GRAPH_ENV_VERSION: 1.3.0
25+
GRAPH_ENV_VERSION: 1.7.0
2826

2927
steps:
3028
- name: Checkout

computer/computer-api/src/main/java/org/apache/hugegraph/computer/core/output/hg/task/TaskManager.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
import org.apache.hugegraph.computer.core.output.hg.exceptions.WriteBackException;
2929
import org.apache.hugegraph.computer.core.output.hg.metrics.LoadSummary;
3030
import org.apache.hugegraph.computer.core.output.hg.metrics.Printer;
31+
import org.apache.hugegraph.computer.core.util.HugeClientUtil;
3132
import org.apache.hugegraph.driver.HugeClient;
32-
import org.apache.hugegraph.driver.HugeClientBuilder;
3333
import org.apache.hugegraph.structure.graph.Vertex;
3434
import org.apache.hugegraph.util.ExecutorUtil;
3535
import org.apache.hugegraph.util.Log;
@@ -58,7 +58,8 @@ public TaskManager(Config config) {
5858
String graph = config.get(ComputerOptions.HUGEGRAPH_GRAPH_NAME);
5959
String username = config.get(ComputerOptions.HUGEGRAPH_USERNAME);
6060
String password = config.get(ComputerOptions.HUGEGRAPH_PASSWORD);
61-
this.client = new HugeClientBuilder(url, graph).configUser(username, password).build();
61+
this.client = HugeClientUtil.newHugeClient(url, graph, username,
62+
password);
6263
// Try to make all batch threads running and don't wait for producer
6364
this.batchSemaphore = new Semaphore(this.batchSemaphoreNum());
6465
/*
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with this
4+
* work for additional information regarding copyright ownership. The ASF
5+
* licenses this file to You under the Apache License, Version 2.0 (the
6+
* "License"); you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hugegraph.computer.core.util;
19+
20+
import java.util.concurrent.atomic.AtomicBoolean;
21+
22+
import org.apache.hugegraph.driver.HugeClient;
23+
import org.apache.hugegraph.driver.HugeClientBuilder;
24+
import org.apache.hugegraph.rest.RestResult;
25+
import org.apache.hugegraph.structure.schema.EdgeLabel;
26+
import org.apache.hugegraph.util.JsonUtil;
27+
28+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
29+
import com.fasterxml.jackson.databind.module.SimpleModule;
30+
31+
public final class HugeClientUtil {
32+
33+
private static final AtomicBoolean COMPATIBILITY_REGISTERED =
34+
new AtomicBoolean(false);
35+
36+
public static HugeClient newHugeClient(String url, String graph,
37+
String username, String password) {
38+
registerCompatibilityModule();
39+
return new HugeClientBuilder(url, graph).configUser(username, password)
40+
.build();
41+
}
42+
43+
public static HugeClient newHugeClient(String url, String graph,
44+
String username, String password,
45+
int timeout) {
46+
registerCompatibilityModule();
47+
return new HugeClientBuilder(url, graph).configUser(username, password)
48+
.configTimeout(timeout)
49+
.build();
50+
}
51+
52+
public static void registerCompatibilityModule() {
53+
if (COMPATIBILITY_REGISTERED.get()) {
54+
return;
55+
}
56+
synchronized (HugeClientUtil.class) {
57+
if (COMPATIBILITY_REGISTERED.get()) {
58+
return;
59+
}
60+
RestResult.registerModule(newCompatibilityModule());
61+
JsonUtil.registerModule(newCompatibilityModule());
62+
COMPATIBILITY_REGISTERED.set(true);
63+
}
64+
}
65+
66+
private static SimpleModule newCompatibilityModule() {
67+
SimpleModule module = new SimpleModule(
68+
"hugegraph-computer-client-compatibility");
69+
module.setMixInAnnotation(EdgeLabel.class, IgnoreUnknownFields.class);
70+
return module;
71+
}
72+
73+
@JsonIgnoreProperties(ignoreUnknown = true)
74+
private abstract static class IgnoreUnknownFields {
75+
}
76+
77+
private HugeClientUtil() {
78+
}
79+
}

computer/computer-core/src/main/java/org/apache/hugegraph/computer/core/input/HugeConverter.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,15 @@
3636
import org.apache.hugegraph.computer.core.graph.value.NullValue;
3737
import org.apache.hugegraph.computer.core.graph.value.StringValue;
3838
import org.apache.hugegraph.computer.core.graph.value.Value;
39+
import org.apache.hugegraph.structure.graph.Edge;
3940
import org.apache.hugegraph.util.E;
41+
import org.apache.hugegraph.util.SplicingIdGenerator;
4042

4143
public final class HugeConverter {
4244

45+
private static final int LEGACY_EDGE_ID_PARTS = 4;
46+
private static final int DIRECTIONAL_EDGE_ID_PARTS = 6;
47+
4348
private static final GraphFactory GRAPH_FACTORY =
4449
ComputerContext.instance().graphFactory();
4550

@@ -96,4 +101,19 @@ public static Properties convertProperties(
96101
}
97102
return properties;
98103
}
104+
105+
public static String convertEdgeName(Edge edge) {
106+
E.checkArgumentNotNull(edge, "The edge can't be null");
107+
String edgeId = edge.id();
108+
if (edgeId == null) {
109+
return edge.name();
110+
}
111+
112+
String[] parts = SplicingIdGenerator.split(edgeId);
113+
if (parts.length >= LEGACY_EDGE_ID_PARTS &&
114+
parts.length <= DIRECTIONAL_EDGE_ID_PARTS) {
115+
return parts[parts.length - 2];
116+
}
117+
return edge.name();
118+
}
99119
}

computer/computer-core/src/main/java/org/apache/hugegraph/computer/core/input/hg/HugeGraphFetcher.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import org.apache.hugegraph.computer.core.input.InputSplit;
2525
import org.apache.hugegraph.computer.core.input.VertexFetcher;
2626
import org.apache.hugegraph.computer.core.rpc.InputSplitRpcService;
27+
import org.apache.hugegraph.computer.core.util.HugeClientUtil;
2728
import org.apache.hugegraph.driver.HugeClient;
28-
import org.apache.hugegraph.driver.HugeClientBuilder;
2929

3030
public class HugeGraphFetcher implements GraphFetcher {
3131

@@ -39,7 +39,8 @@ public HugeGraphFetcher(Config config, InputSplitRpcService rpcService) {
3939
String graph = config.get(ComputerOptions.HUGEGRAPH_GRAPH_NAME);
4040
String username = config.get(ComputerOptions.HUGEGRAPH_USERNAME);
4141
String password = config.get(ComputerOptions.HUGEGRAPH_PASSWORD);
42-
this.client = new HugeClientBuilder(url, graph).configUser(username, password).build();
42+
this.client = HugeClientUtil.newHugeClient(url, graph, username,
43+
password);
4344
this.vertexFetcher = new HugeVertexFetcher(config, this.client);
4445
this.edgeFetcher = new HugeEdgeFetcher(config, this.client);
4546
this.rpcService = rpcService;

computer/computer-core/src/main/java/org/apache/hugegraph/computer/core/input/hg/HugeInputSplitFetcher.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
import org.apache.hugegraph.computer.core.config.Config;
2525
import org.apache.hugegraph.computer.core.input.InputSplit;
2626
import org.apache.hugegraph.computer.core.input.InputSplitFetcher;
27+
import org.apache.hugegraph.computer.core.util.HugeClientUtil;
2728
import org.apache.hugegraph.driver.HugeClient;
28-
import org.apache.hugegraph.driver.HugeClientBuilder;
2929
import org.apache.hugegraph.structure.graph.Shard;
3030
import org.apache.hugegraph.util.E;
3131

@@ -41,9 +41,8 @@ public HugeInputSplitFetcher(Config config) {
4141
String username = config.get(ComputerOptions.HUGEGRAPH_USERNAME);
4242
String password = config.get(ComputerOptions.HUGEGRAPH_PASSWORD);
4343
int timeout = config.get(ComputerOptions.INPUT_SPLIT_FETCH_TIMEOUT);
44-
this.client = new HugeClientBuilder(url, graph).configUser(username, password)
45-
.configTimeout(timeout)
46-
.build();
44+
this.client = HugeClientUtil.newHugeClient(url, graph, username,
45+
password, timeout);
4746
}
4847

4948
@Override

computer/computer-core/src/main/java/org/apache/hugegraph/computer/core/worker/load/LoadService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ private Edge convert(org.apache.hugegraph.structure.graph.Edge edge) {
238238
Properties properties = HugeConverter.convertProperties(
239239
edge.properties());
240240
Edge computerEdge = graphFactory.createEdge(edge.label(),
241-
edge.name(), targetId
241+
HugeConverter.convertEdgeName(edge),
242+
targetId
242243
);
243244
computerEdge.label(edge.label());
244245
computerEdge.properties(properties);

computer/computer-test/src/main/java/org/apache/hugegraph/computer/core/input/HugeConverterTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
import org.apache.hugegraph.computer.core.graph.value.StringValue;
3636
import org.apache.hugegraph.computer.core.graph.value.ValueType;
3737
import org.apache.hugegraph.computer.suite.unit.UnitTestBase;
38+
import org.apache.hugegraph.structure.graph.Edge;
3839
import org.apache.hugegraph.testutil.Assert;
3940
import org.junit.Test;
41+
import org.mockito.Mockito;
4042

4143
import com.google.common.collect.ImmutableList;
4244

@@ -126,4 +128,74 @@ public void testConvertProperties() {
126128
Assert.assertEquals(properties,
127129
HugeConverter.convertProperties(rawProperties));
128130
}
131+
132+
@Test
133+
public void testConvertEdgeNameWithLegacyFourPartEdgeId() {
134+
Edge edge = Mockito.mock(Edge.class);
135+
Mockito.when(edge.id()).thenReturn(
136+
"S1:178201>5>参数标准!3BA0>S4:239464");
137+
Mockito.when(edge.name()).thenReturn("stale_client_name");
138+
139+
Assert.assertEquals("参数标准!3BA0",
140+
HugeConverter.convertEdgeName(edge));
141+
}
142+
143+
@Test
144+
public void testConvertEdgeNameWithFivePartEdgeId() {
145+
Edge edge = new Edge("belong_to_el_defect");
146+
edge.id("S1:178201>5>5>参数标准!3BA0>S4:239464");
147+
148+
Assert.assertEquals("参数标准!3BA0",
149+
HugeConverter.convertEdgeName(edge));
150+
}
151+
152+
@Test
153+
public void testConvertEdgeNameWithSixPartEdgeId() {
154+
Edge edge = new Edge("belong_to_el_defect");
155+
edge.id("S1:178201>O>5>5>参数标准!3BA0>S4:239464");
156+
157+
Assert.assertEquals("参数标准!3BA0",
158+
HugeConverter.convertEdgeName(edge));
159+
}
160+
161+
@Test
162+
public void testConvertEdgeNameWithSixPartInEdgeId() {
163+
Edge edge = new Edge("belong_to_el_defect");
164+
edge.id("S4:239464>I>5>5>参数标准!3BA0>S1:178201");
165+
166+
Assert.assertEquals("参数标准!3BA0",
167+
HugeConverter.convertEdgeName(edge));
168+
}
169+
170+
@Test
171+
public void testConvertEdgeNameWithNullEdgeId() {
172+
Edge edge = Mockito.mock(Edge.class);
173+
Mockito.when(edge.id()).thenReturn(null);
174+
Mockito.when(edge.name()).thenReturn("fallback_name");
175+
176+
Assert.assertEquals("fallback_name",
177+
HugeConverter.convertEdgeName(edge));
178+
}
179+
180+
@Test
181+
public void testConvertEdgeNameWithUnknownEdgeIdFormat() {
182+
Edge edge = Mockito.mock(Edge.class);
183+
Mockito.when(edge.id()).thenReturn(
184+
"S1:178201>bad>edge");
185+
Mockito.when(edge.name()).thenReturn("fallback_name");
186+
187+
Assert.assertEquals("fallback_name",
188+
HugeConverter.convertEdgeName(edge));
189+
190+
Mockito.when(edge.id()).thenReturn(
191+
"S1:178201>O>5>5>参数标准!3BA0>S4:239464>extra");
192+
Assert.assertEquals("fallback_name",
193+
HugeConverter.convertEdgeName(edge));
194+
}
195+
196+
@Test
197+
public void testConvertEdgeNameWithNullEdge() {
198+
Assert.assertThrows(IllegalArgumentException.class,
199+
() -> HugeConverter.convertEdgeName(null));
200+
}
129201
}

computer/computer-test/src/main/java/org/apache/hugegraph/computer/core/input/InputTestSuite.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.hugegraph.computer.core.input;
1919

20+
import org.apache.hugegraph.computer.core.input.hg.HugeClientCompatibilityTest;
2021
import org.junit.runner.RunWith;
2122
import org.junit.runners.Suite;
2223

@@ -25,7 +26,8 @@
2526
InputSplitTest.class,
2627
FileInputSplitTest.class,
2728
InputSplitDataTest.class,
28-
HugeConverterTest.class
29+
HugeConverterTest.class,
30+
HugeClientCompatibilityTest.class
2931
})
3032
public class InputTestSuite {
3133
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with this
4+
* work for additional information regarding copyright ownership. The ASF
5+
* licenses this file to You under the Apache License, Version 2.0 (the
6+
* "License"); you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.hugegraph.computer.core.input.hg;
19+
20+
import java.lang.reflect.Method;
21+
22+
import org.apache.hugegraph.computer.core.util.HugeClientUtil;
23+
import org.apache.hugegraph.rest.RestResult;
24+
import org.apache.hugegraph.structure.schema.EdgeLabel;
25+
import org.apache.hugegraph.testutil.Assert;
26+
import org.junit.Test;
27+
28+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
29+
import com.fasterxml.jackson.databind.ObjectMapper;
30+
import com.fasterxml.jackson.databind.module.SimpleModule;
31+
32+
public class HugeClientCompatibilityTest {
33+
34+
@Test
35+
public void testReadEdgeLabelWithCurrentServerFields() {
36+
HugeClientUtil.registerCompatibilityModule();
37+
38+
String content = "{" +
39+
"\"id\":1," +
40+
"\"name\":\"link\"," +
41+
"\"edgelabel_type\":\"NORMAL\"," +
42+
"\"source_label\":\"user\"," +
43+
"\"target_label\":\"user\"," +
44+
"\"links\":[{\"user\":\"user\"}]," +
45+
"\"frequency\":\"SINGLE\"," +
46+
"\"sort_keys\":[]," +
47+
"\"nullable_keys\":[]," +
48+
"\"index_labels\":[]," +
49+
"\"properties\":[]," +
50+
"\"status\":\"CREATED\"," +
51+
"\"ttl\":0," +
52+
"\"enable_label_index\":true," +
53+
"\"user_data\":{\"~create_time\":\"2026-06-22 15:26:42.781\"}" +
54+
"}";
55+
56+
EdgeLabel edgeLabel = new RestResult(200, content, null).readObject(
57+
EdgeLabel.class);
58+
59+
Assert.assertEquals("link", edgeLabel.name());
60+
Assert.assertEquals("user", edgeLabel.sourceLabel());
61+
Assert.assertEquals("user", edgeLabel.targetLabel());
62+
}
63+
64+
@Test
65+
public void testEdgeLabelCompatibilityUsesIgnoreUnknownMixin()
66+
throws Exception {
67+
ObjectMapper mapper = new ObjectMapper();
68+
mapper.registerModule(newCompatibilityModule());
69+
70+
Class<?> mixIn = mapper.getDeserializationConfig()
71+
.findMixInClassFor(EdgeLabel.class);
72+
JsonIgnoreProperties annotation = mixIn.getAnnotation(
73+
JsonIgnoreProperties.class);
74+
75+
Assert.assertTrue(annotation.ignoreUnknown());
76+
}
77+
78+
private static SimpleModule newCompatibilityModule() throws Exception {
79+
Method method = HugeClientUtil.class.getDeclaredMethod(
80+
"newCompatibilityModule");
81+
method.setAccessible(true);
82+
return (SimpleModule) method.invoke(null);
83+
}
84+
}

0 commit comments

Comments
 (0)