-
Notifications
You must be signed in to change notification settings - Fork 504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support batch updating elements' property by multiple strategy #493
Conversation
imbajin
commented
Apr 30, 2019
- Hard code to get elementId now
- Edge's Direction is always OUT now
- Other TODOs need finish later (add more unit-test also)
Codecov Report
@@ Coverage Diff @@
## master #493 +/- ##
=========================================
Coverage 71.41% 71.41%
Complexity 3528 3528
=========================================
Files 216 216
Lines 16657 16657
Branches 2379 2379
=========================================
Hits 11895 11895
Misses 3512 3512
Partials 1250 1250
Continue to review full report at Codecov.
|
} | ||
|
||
public static UpdateStrategy valueOf(Object strategy) { | ||
E.checkState(strategy instanceof String, "UpdateStrategy must be " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap line after ","
* TODO: Adapter for createIfNotExist | ||
* Batch update steps are same like vertices | ||
**/ | ||
@POST |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use PUT and let jsonEdges = {edges: [...]}
public String update(@Context HugeConfig config, | ||
@Context GraphManager manager, | ||
@PathParam("graph") String graph, | ||
@QueryParam("updateStrategies") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move all QueryParams to json body
String key = kv.getKey(); | ||
if (oldElement.properties.get(key) != null) { | ||
Object value = UpdateStrategy.checkAndUpdateProperty( | ||
oldElement.properties.get(key), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer to align with UpdateStrategy
} | ||
} | ||
|
||
protected void operateProperties(JsonElement jsonElement, boolean append, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
set static and rename to updateProperties()
public enum UpdateStrategy { | ||
|
||
//Only number support accumlate | ||
ACCUMULATE { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SUM is more readable
@Override | ||
void checkPropertyType(Object oldProperty, Object newProperty) { | ||
E.checkState((oldProperty instanceof Date || | ||
oldProperty instanceof Long) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oldProperty instanceof Number?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have thought about it before, but the timestamp with milliseconds can only be Long, the unattached is also close to the upper limit of Integer, and it should only allow Integer or Long? The range of Number seems too wide
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can use method compareNumber() from hugegraph-common directly: com.baidu.hugegraph.util.NumericUtil.compareNumber(Object first, Number second)
and call com.baidu.hugegraph.util.NumericUtil.convertToNumber(Object value)
to convert an object to a number.
E.checkState((oldProperty instanceof Date || | ||
oldProperty instanceof Long) && | ||
(newProperty instanceof Date || | ||
newProperty instanceof Long), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
} | ||
}, | ||
|
||
// TODO: Merge from "action", how to handle List? (have same elements) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ELIMINATE all the same elements
if (oldElement.property(key).isPresent()) { | ||
Object value = UpdateStrategy.checkAndUpdateProperty( | ||
oldElement.property(key).value(), | ||
element.properties.get(key), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let new property value be converted by property-key like this pkey.convValue(value, false)
how to get property-key: graph.propertyKey(name)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let new property value be converted by property-key like this pkey.convValue(value, false)
how to get property-key:
graph.propertyKey(name)
is it like value = g.propertyKey(key).convValue(value, false)
? Wonder why need to convert pkValue again? or just for safety?
PS: disappear for some days, and back now~ (will fix them soon)
hugegraph-api/src/main/java/com/baidu/hugegraph/api/graph/EdgeAPI.java
Outdated
Show resolved
Hide resolved
hugegraph-api/src/main/java/com/baidu/hugegraph/api/graph/BatchAPI.java
Outdated
Show resolved
Hide resolved
hugegraph-api/src/main/java/com/baidu/hugegraph/api/graph/BatchAPI.java
Outdated
Show resolved
Hide resolved
* TODO: Should support AUTOMATIC ElementID ? | ||
* TODO: How to get JsonEdge's fields ? | ||
*/ | ||
protected String getElementId(HugeGraph g, String labelId, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems can split into two methods directly: getVertexId(g, label, JsonVertex) and getEdgeId(g, label, JsonEdge).
can avoid the method too long and reduce the number of parameters.
If need, move getVertexId into VertexAPI, getEdgeId into EdgeAPI
|
||
/** | ||
* Get vertex/edge ID from JsonVerex/JsonEdge | ||
* TODO: Should support AUTOMATIC ElementID ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AUTOMATIC ElementID -> AUTOMATIC Id strategy, similar in other places
JsonElement newElement, | ||
Map<String, UpdateStrategy> strategy) { | ||
if (oldElement != null && newElement != null) { | ||
strategy.entrySet().forEach(kv -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic-critical code uses a normal for loop instead of forEach
checkBatchSize(config, jsonEdges); | ||
|
||
Map<String, JsonEdge> maps = new HashMap<>(jsonEdges.size()); | ||
Map<String, Object> strategies = parseProperties(updateStrategies); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Define a class wrap all QueryParams and jsonEdges, then deserialize UpdateStrategies will be easy. you can refer
CustomizedPathsAPI.PathRequest
1f2ff21
to
be2b8b3
Compare
Iterator<Edge> oldEdges = g.edges(ids.toArray()); | ||
oldEdges.forEachRemaining(oldEdge -> { | ||
updateExistElement(oldEdge, | ||
maps.get(oldEdge.id().toString()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we change Map<String, JsonEdge> to Map<Id, JsonEdge>?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first I want to use a common method called getElementId
to get EdgeId & VertexId together, so I use String for both
now the methods are separated. maybe use Map<Object, JsonVertex>
& Map<String, JsonEdge>
is more simple because JsonVertex & JsonEdge 's id
property's type isObject
& String
.
if use Id
type for them, both of them need to convert again, but seems unnecessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both Edge Id and Vertex Id are instance of Id, EdgeId is a subclass of id.
@Override | ||
public String toString() { | ||
return String.format("EdgeRequest{jsonEdges=%s,updateStrategies" + | ||
"=%s,check_vertex=%s,createIfNotExist=%s}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check_vertex => checkVertex (in java code)
and prefer to move "=%s," to the previous line
oldProperty instanceof Number) && | ||
(newProperty instanceof Date || | ||
newProperty instanceof Number), | ||
formatError(oldProperty, newProperty, "Date or " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap line after ","
JsonElement newElement, | ||
Map<String, UpdateStrategy> strategy, | ||
HugeGraph g) { | ||
if (oldElement != null && newElement != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.checkArgment(oldElement != null && newElement != null, "...");
oldElement.property(key).value(), | ||
newElement.properties.get(key)); | ||
newElement.properties.put(key, g.propertyKey(key). | ||
convValue(value,false)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing a space
prefer to use value = g.propertyKey(key).convValue(value, false)
protected void updateExistElement(Element oldElement, | ||
JsonElement newElement, | ||
Map<String, UpdateStrategy> strategy, | ||
HugeGraph g) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let "HugeGraph g" as first parameter
for (Id pkId : pkIds) { | ||
String propertyKey = g.propertyKey(pkId).name(); | ||
Object propertyValue = vertex.properties.get(propertyKey); | ||
E.checkState(propertyValue != null, "The value of primary key " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrap line after ","
SUM { | ||
@Override | ||
Object updatePropertyValue(Object oldProperty, Object newProperty) { | ||
// TODO: How to accumulae universally (Byte, Long,...Double) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use bigdecimal: https://www.tutorialspoint.com/java/math/bigdecimal_add_augend.htm
Iterator<Edge> oldEdges = g.edges(ids.toArray()); | ||
oldEdges.forEachRemaining(oldEdge -> { | ||
updateExistElement(oldEdge, | ||
maps.get(oldEdge.id().toString()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both Edge Id and Vertex Id are instance of Id, EdgeId is a subclass of id.
|
||
private static String formatError(Object oldProperty, Object newProperty, | ||
String className) { | ||
return String.format("Property must be" + className + "type, but got " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Property must be % type, ..."
(result < 0 ? oldProperty : newProperty); | ||
} | ||
|
||
private static Set comparedSet(Object oldProperty, Object newProperty, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer rename to combineSet()
}); | ||
|
||
// If return ids, the ids.size() maybe different with the origins' | ||
return manager.serializer(g). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep "." at the head of next line and align with ".serializer()"
@JsonIgnoreProperties(value = {"type"}) | ||
private static class JsonVertex implements Checkable { | ||
//TODO: Should support AUTOMATIC Id strategy ? | ||
private Object getVertexId(HugeGraph g, String labelId, JsonVertex vertex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If let getVertexId() return Id then it can be more simple and unified in the future.
@@ -350,25 +404,63 @@ public static Direction parseDirection(String direction) { | |||
} | |||
} | |||
|
|||
@JsonIgnoreProperties(value = {"type"}) | |||
private static class JsonEdge implements Checkable { | |||
private String getEdgeId(HugeGraph g, Id labelId, JsonEdge newEdge) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as getVertexId()
Directions.OUT, | ||
g.edgeLabel(newEdge.label).id(), sortKeys, | ||
HugeVertex.getIdValue(newEdge.target)); | ||
return edgeId.asString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return edgeId itself
// 1.Put all newEdges' properties into map (combine first) | ||
req.jsonEdges.forEach(newEdge -> { | ||
Id labelId = g.edgeLabel(newEdge.label).id(); | ||
String id = newEdge.id != null ? newEdge.id : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Id id = newEdge.id != null ? EdgeId.parse(newEdge.id)
@@ -71,4 +78,75 @@ public BatchAPI() { | |||
batchWriteThreads.decrementAndGet(); | |||
} | |||
} | |||
|
|||
// TODO: Design more flexible for Element? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems unused TODO
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering if I could make it easier to merge JsonElement
& Element
by extends or implements a class, will del it
} | ||
} | ||
|
||
// TODO: Combine multi update methond into one (Element & JsonElement) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove TODO since we can't combine them
req.jsonVertices.forEach(newVertex -> { | ||
String labelId = g.vertexLabel(newVertex.label).id().asString(); | ||
Object id = newVertex.id != null ? newVertex.id : | ||
this.getVertexId(g, labelId, newVertex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just let Id id = this.getVertexId(g, labelId, newVertex);
} | ||
|
||
String name = SplicingIdGenerator.concatValues(pkValues); | ||
return SplicingIdGenerator.splicing(labelId, name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object idValue = newVertex.id != null ? newVertex.id : SplicingIdGenerator.splicing(labelId, name)
return HugeVertex.getIdValue(idValue)
// TODO: How to get Direction from JsonEdge easily? or any better way? | ||
EdgeId edgeId = new EdgeId(HugeVertex.getIdValue(newEdge.source), | ||
Directions.OUT, | ||
g.edgeLabel(newEdge.label).id(), sortKeys, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use labelId instead
req.jsonVertices.forEach(newVertex -> { | ||
String labelId = g.vertexLabel(newVertex.label).id().asString(); | ||
Object id = newVertex.id != null ? newVertex.id : | ||
this.getVertexId(g, labelId, newVertex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just let Id id = this.getVertexId(g, labelId, newVertex);
hugegraph-api/src/main/java/com/baidu/hugegraph/api/graph/VertexAPI.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
// TODO: Combine multi update methond into one (Element & JsonElement) | ||
protected void updateExistElement(HugeGraph graph, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep consistent style HugeGraph g
* - Consider primary-key & user-define ID mode first | ||
* */ | ||
req.jsonVertices.forEach(newVertex -> { | ||
String labelId = g.vertexLabel(newVertex.label).id().asString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems doesn't need to define labelId, and getVertexId(g, newVertex) is enough
HugeGraph g = graph(manager, graph); | ||
checkBatchSize(config, req.jsonVertices); | ||
// Not support automatic Id strategy now (check once?) | ||
E.checkArgument(g.vertexLabel(req.jsonVertices.get(0).label). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need check all vertices id strategy
req.jsonVertices.forEach(newVertex -> { | ||
String labelId = g.vertexLabel(newVertex.label).id().asString(); | ||
Id id = this.getVertexId(g, labelId, newVertex); | ||
this.updateExistElement(newVertex, maps.get(id), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the parameter reversed? I think it should be this.updateExistElement(maps.get(id), newVertex, req.updateStrategies)
private Id getVertexId(HugeGraph g, String labelId, JsonVertex vertex) { | ||
assert g.vertexLabel(labelId).idStrategy() != IdStrategy.AUTOMATIC; | ||
|
||
List<Id> pkIds = g.vertexLabel(vertex.label).primaryKeys(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer using if-else according to the id strategy, like
if (CUSTOMIZED) {
xxx
} else {
assert PRIMARY_KEY
xxx
}
Clear logic is better than code clean
Iterator<Vertex> oldVertices = g.vertices(ids.toArray()); | ||
oldVertices.forEachRemaining(oldVertex -> { | ||
updateExistElement(g, oldVertex, | ||
maps.get(oldVertex.id()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems define a local var is more readable
JsonVertex newVertex = maps.get(oldVertex.id());
updateExistElement(g, oldVertex, newVertex,
req.updateStrategies);
}); | ||
|
||
// 2.Get all oldVertices and update with new vertices | ||
List<Id> ids = new ArrayList<>(maps.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object[] ids = maps.keySet().toArray();
"the maximum number is '%s'", max)); | ||
} | ||
} | ||
|
||
@JsonIgnoreProperties(value = {"type"}) | ||
private static class JsonVertex implements Checkable { | ||
private Id getVertexId(HugeGraph g, String labelId, JsonVertex vertex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove param labelId
|
||
private static class VertexRequest { | ||
|
||
@JsonProperty("jsonVertices") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RESTful API params use underlined style, EdgeAPI is an exception, in order to follow the specifications of tinkerpop
@JsonProperty("jsonVertices") -> @JsonProperty("vertices")
@JsonProperty("updateStrategies") -> @JsonProperty("update_strategies")
@JsonProperty("create") -> @JsonProperty("create_if_not_exist")
@@ -350,25 +404,61 @@ public static Direction parseDirection(String direction) { | |||
} | |||
} | |||
|
|||
@JsonIgnoreProperties(value = {"type"}) | |||
private static class JsonEdge implements Checkable { | |||
private Id getEdgeId(HugeGraph g, Id labelId, JsonEdge newEdge) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of the comments in VertexAPI also applied here.
Ugh, seems CI failed, please fix https://travis-ci.org/hugegraph/hugegraph/jobs/536220267 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
seems need add constructor for JsonVertex and JsonEdge
checkBatchSize(config, req.jsonEdges); | ||
|
||
HugeGraph g = graph(manager, graph); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good change
} | ||
} | ||
|
||
private class JsonVertex extends JsonElement { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private static class
can pass test!!!
Map<Id, JsonEdge> maps = new HashMap<>(req.jsonEdges.size()); | ||
TriFunction<HugeGraph, Object, String, Vertex> getVertex = | ||
req.checkVertex ? EdgeAPI::getVertex : EdgeAPI::newVertex; | ||
|
||
return this.commit(config, g, maps.size(), () -> { | ||
|
||
// 1.Put all newEdges' properties into map (combine first) | ||
// 1.Put all newEdges' properties into map (combine first) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove empty line
Id id = newEdge.id != null ? EdgeId.parse(newEdge.id) : | ||
this.getEdgeId(g, labelId, newEdge); | ||
this.updateExistElement(newEdge, maps.get(id), | ||
Id newEdgeId = newEdge.id != null ? EdgeId.parse(newEdge.id) : |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move "newEdge.id != null ? EdgeId.parse(newEdge.id)" into getEdgeId():
if (newEdge.id != null) {
return EdgeId.parse(newEdge.id);
}
and just let Id newEdgeId = getEdgeId(g, newEdge);
protected void updateExistElement(HugeGraph g, | ||
Element oldElement, | ||
JsonElement newElement, | ||
Map<String, UpdateStrategy> strategy) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to strategies
|
||
protected void updateExistElement(JsonElement oldElement, | ||
JsonElement newElement, | ||
Map<String, UpdateStrategy> strategy) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to strategies
|
||
protected static void updateProperties(JsonElement jsonElement, | ||
boolean append, | ||
HugeElement element) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer to set HugeElement element
as the first parameter
checkBatchSize(config, req.jsonEdges); | ||
|
||
HugeGraph g = graph(manager, graph); | ||
Map<Id, JsonEdge> maps = new HashMap<>(req.jsonEdges.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map or edges
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
address the comment
checkBatchSize(config, req.jsonVertices); | ||
|
||
HugeGraph g = graph(manager, graph); | ||
Map<Id, JsonVertex> maps = new HashMap<>(req.jsonVertices.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to vertices or map
|
||
@Override | ||
void checkPropertyType(Object oldProperty, Object newProperty) { | ||
E.checkState(oldProperty instanceof Number && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update to E.checkArgument(), same as other checks in UpdateStrategy
|
||
@Override | ||
void checkPropertyType(Object oldProperty, Object newProperty) { | ||
BIGGER.checkPropertyType(oldProperty, newProperty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it makes sense to call BIGGER.checkPropertyType
|
||
private static String formatError(Object oldProperty, Object newProperty, | ||
String className) { | ||
return String.format("Property must be %s type, but got %s, %s", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to Property type must be %s
String key = kv.getKey(); | ||
UpdateStrategy updateStrategy = kv.getValue(); | ||
if (oldElement.property(key).isPresent()) { | ||
if (oldElement.property(key).isPresent() && | ||
newElement.properties.get(key) != null ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace newElement.properties.get(key) != null
to newElement.properties.containsKey(key)
and remove space before " )"
checkBatchSize(config, req.jsonEdges); | ||
|
||
HugeGraph g = graph(manager, graph); | ||
Map<Id, JsonEdge> maps = new HashMap<>(req.jsonEdges.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
address the comment
APPEND { | ||
@Override | ||
Object updatePropertyValue(Object oldProperty, Object newProperty) { | ||
return ((Collection) oldProperty).addAll((Collection) newProperty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addAll() returns boolean value, seems should return oldProperty.
ELIMINATE { | ||
@Override | ||
Object updatePropertyValue(Object oldProperty, Object newProperty) { | ||
return ((Collection) oldProperty).removeAll |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
(result < 0 ? oldProperty : newProperty); | ||
} | ||
|
||
private static Set combineSet(Object oldProperty, Object newProperty, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add template parameter like Set<?>
} | ||
}, | ||
|
||
// TODO: Unify "action" in Vertex/EdgeAPI later |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused TODO?
205fd75
to
7fd96eb
Compare
} | ||
} | ||
|
||
private static class JsonVertex extends JsonElement { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
override equals() & hashCode() method.
equals(JsonEdge other): return this.id.equals(other.id)
hashCode(): return this.id.hashCode()
Note: make sure that update JsonVertex.id in getVertexId() method.
The same as JsonEdge class, maybe it's better to move id field to JsonElement class.
@@ -125,7 +125,7 @@ protected void updateExistElement(HugeGraph g, | |||
String key = kv.getKey(); | |||
UpdateStrategy updateStrategy = kv.getValue(); | |||
if (oldElement.property(key).isPresent() && | |||
newElement.properties.get(key) != null ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remember to modify these:
- hugegraph-api pom.xml
<Implementation-Version>0.39.0.0</Implementation-Version>
to<Implementation-Version>0.40.0.0</Implementation-Version>
- hugegraph-api ApiVersion.class
0.39
to0.40
, and add an item under[0.39] Issue-522: Add profile RESTful API
, write something like[0.40] Issue-493: Support batch updating elements' property by multiple strategy
1. Hard code to get elementId now 2. Edge's Direction is always OUT now 3. Other TODOs need finish later (add more unit-test also) 4. Move params to Vertex/EdgeRequest
The type of EdgeId is still String because of complexity of conversion
Tests show that @NotNull can't intercept null-objcet successfully.
7fd96eb
to
e7fc6af
Compare
@@ -87,10 +87,12 @@ | |||
* | |||
* version 0.10: | |||
* [0.39] Issue-522: Add profile RESTful API | |||
* [0.40] Issue-493: Support batch updating elements' property by multiple | |||
* strategy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep on one line
return edgeId; | ||
} | ||
|
||
protected static class EdgeRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BatchEdgeRequest
} | ||
} | ||
|
||
private static class VertexRequest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BatchVertexRequest
protected void updateExistElement(JsonElement oldElement, | ||
JsonElement newElement, | ||
Map<String, UpdateStrategy> strategies) { | ||
if (oldElement != null && newElement != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return if oldElement is null
and check newElement != null
@@ -114,6 +115,64 @@ public String create(@Context GraphManager manager, | |||
}); | |||
} | |||
|
|||
/** | |||
* TODO: Adapter for param("createIfNotExist") or delete it? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we really don't use this parameter, just delete it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Linary any suggestion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete it first, consider it when inneed
protected static abstract class JsonElement implements Checkable { | ||
|
||
@JsonProperty("id") | ||
public Id id; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use object instead, otherwise it will throw error as follows
Can not construct instance of com.baidu.hugegraph.backend.id.Id: abstract types either need to be mapped to concrete types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace Id with Object
|
||
// Batch update Set should use union because of higher efficiency | ||
APPEND { | ||
@Override |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add
@SuppressWarnings({ "rawtypes", "unchecked" })
}, | ||
|
||
ELIMINATE { | ||
@Override |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
Set newSet = newProperty instanceof Set ? | ||
(Set) newProperty : new HashSet((List) newProperty); | ||
return strategy == UNION ? Sets.union(oldSet, newSet) : | ||
Sets.intersection(oldSet, newSet); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set is a raw type. References to generic type Set should be parameterized.
please update to:
Set<?> oldSet = oldProperty instanceof Set ?
(Set<?>) oldProperty :
new HashSet<>((List<?>) oldProperty);
Set<?> newSet = newProperty instanceof Set ?
(Set<?>) newProperty :
new HashSet<>((List<?>) newProperty);
return strategy == UNION ? Sets.union(oldSet, newSet) :
Sets.intersection(oldSet, newSet);
@@ -112,6 +112,7 @@ void checkPropertyType(Object oldProperty, Object newProperty) { | |||
}, | |||
|
|||
// Batch update Set should use union because of higher efficiency | |||
@SuppressWarnings({ "rawtypes", "unchecked" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to line 118
@@ -125,6 +126,7 @@ void checkPropertyType(Object oldProperty, Object newProperty) { | |||
} | |||
}, | |||
|
|||
@SuppressWarnings({ "rawtypes", "unchecked" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
/* | ||
* 1.Put all newVertices' properties into map (combine first) | ||
* - Consider primary-key & user-define ID mode first | ||
* */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra *
…hugegraph into support-update-strategy
Collection<? extends Checkable> bodys) { | ||
E.checkArgumentNotNull(bodys, "The request body can't be empty"); | ||
for (Checkable body : bodys) { | ||
E.checkArgumentNotNull(body, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor improve to shorten the length:
E.checkArgument(body != null,
@@ -157,6 +159,64 @@ public String create(@Context GraphManager manager, | |||
}); | |||
} | |||
|
|||
/** | |||
* Batch update steps are same like vertices | |||
**/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra *
* 1. Get all newVertices' ID & combine first | ||
* 2. Get all oldVertices & update | ||
* 3. Add the final vertex together | ||
**/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
for (Id pkId : pkIds) { | ||
String propertyKey = g.propertyKey(pkId).name(); | ||
Object propertyValue = vertex.properties.get(propertyKey); | ||
E.checkState(propertyValue != null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.checkArgument
sortKeyIds.forEach(skId -> { | ||
String sortKey = g.propertyKey(skId).name(); | ||
Object sortKeyValue = newEdge.properties.get(sortKey); | ||
E.checkState(sortKeyValue != null, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.checkArgument
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some minor comments
public boolean createIfNotExist = true; | ||
|
||
private static void checkUpdate(BatchVertexRequest req) { | ||
E.checkArgumentNotNull(req, "BatchVertexRequest cannot be null"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prefer to replace all "cannot" to "can't"
@@ -259,22 +307,70 @@ private static void checkBatchSize(HugeConfig config, | |||
int max = config.get(ServerOptions.MAX_VERTICES_PER_BATCH); | |||
if (vertices.size() > max) { | |||
throw new IllegalArgumentException(String.format( | |||
"Too many counts of vertices for one time post, " + | |||
"Too many vertices for one time post, " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add check vertices.size() == 0
|
||
public Object checkAndUpdateProperty(Object oldProperty, | ||
Object newProperty) { | ||
checkPropertyType(oldProperty, newProperty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tiny improve: this.checkPropertyType()
public Object checkAndUpdateProperty(Object oldProperty, | ||
Object newProperty) { | ||
checkPropertyType(oldProperty, newProperty); | ||
return updatePropertyValue(oldProperty, newProperty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.updatePropertyValue()
@PathParam("graph") String graph, | ||
BatchVertexRequest req) { | ||
BatchVertexRequest.checkUpdate(req); | ||
LOG.debug("Graph [{}] update vertices: {}", graph, req.jsonVertices); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log req instead of req.jsonVertices
@PathParam("graph") String graph, | ||
BatchEdgeRequest req) { | ||
BatchEdgeRequest.checkUpdate(req); | ||
LOG.debug("Graph [{}] update edges: {}", graph, req.jsonEdges); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
"Parameter 'update_strategies' cannot be empty"); | ||
E.checkArgument(req.createIfNotExist == true, | ||
"Parameter 'create_if_not_exist' " + | ||
"dose not supported false now"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dose not support
"Parameter 'update_strategies' cannot be empty"); | ||
E.checkArgument(req.createIfNotExist == true, | ||
"Parameter 'create_if_not_exist' " + | ||
"dose not supported false now"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dose not support
Object sortKeyValue = newEdge.properties.get(sortKey); | ||
E.checkArgument(sortKeyValue != null, | ||
"The value of sort key '%s' can't be null", | ||
skId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
skId->sortKey
hugegraph-api/src/main/java/com/baidu/hugegraph/api/graph/UpdateStrategy.java
Show resolved
Hide resolved
hugegraph-api/src/main/java/com/baidu/hugegraph/api/graph/UpdateStrategy.java
Outdated
Show resolved
Hide resolved
|
||
private static String formatError(Object oldProperty, Object newProperty, | ||
String className) { | ||
return String.format("Property must be %s, but got %s, %s", className, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove static and make error message more clear, like:
Property type must be %s for strategy %s, but got %s
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use javap -v
to decompile the class, and find a interesting thing :
formatError()
is referenced by a synthetic static method because the inner-class cannot call private method outside. If remove static, we have to make it be non-private (expand the access of method)
And if we choose to do so, seems we can change the other 2 methods(compareNumber
& combineSet
) from private static
to package-default
, it also reduces the method calls & number :)
Reference : java-synthetic-methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
making it protected is ok. I think clear error message is more important.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
making it protected is ok. I think clear error message is more important.
done, has unified them with non-static methods, and since enum
cannot be inherited ,seems default modifier is enough.
9f7911f
to
771ad3f
Compare
formatError(oldProperty, newProperty, | ||
"Set or List")); | ||
this.formatError(oldProperty, newProperty, | ||
this, "Set or List")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary to pass this
String formatError(Object oldProperty, Object newProperty, | ||
UpdateStrategy strategy, String className) { | ||
return String.format("Property type must be %s for strategy %s, " + | ||
"but got type %s, %s", className, strategy, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just use this instead of strategy parameter
oldProperty.getClass().getSimpleName(), | ||
newProperty.getClass().getSimpleName()); | ||
} | ||
|
||
private static Object compareNumber(Object oldProperty, Object newProperty, | ||
UpdateStrategy strategy) { | ||
Object compareNumber(Object oldProperty, Object newProperty, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep private static
884a886
to
59722ad
Compare