Skip to content
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

Merged
merged 24 commits into from
Jul 23, 2019

Conversation

imbajin
Copy link
Member

@imbajin imbajin commented Apr 30, 2019

  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)

@codecov
Copy link

codecov bot commented Apr 30, 2019

Codecov Report

Merging #493 into master will not change coverage.
The diff coverage is 0%.

Impacted file tree graph

@@            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
Impacted Files Coverage Δ Complexity Δ
...hugegraph/backend/serializer/BinarySerializer.java 80.09% <ø> (ø) 104 <0> (ø) ⬇️
...h/backend/store/rocksdbsst/RocksDBSstSessions.java 0% <0%> (ø) 0 <0> (ø) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ffb09f1...454e123. Read the comment docs.

}

public static UpdateStrategy valueOf(Object strategy) {
E.checkState(strategy instanceof String, "UpdateStrategy must be " +
Copy link
Contributor

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
Copy link
Contributor

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")
Copy link
Contributor

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),
Copy link
Contributor

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,
Copy link
Contributor

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 {
Copy link
Contributor

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) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oldProperty instanceof Number?

Copy link
Member Author

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

Copy link
Contributor

@javeme javeme May 7, 2019

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),
Copy link
Contributor

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)
Copy link
Contributor

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),
Copy link
Contributor

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)

Copy link
Member Author

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)

* TODO: Should support AUTOMATIC ElementID ?
* TODO: How to get JsonEdge's fields ?
*/
protected String getElementId(HugeGraph g, String labelId,
Copy link
Contributor

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 ?
Copy link
Contributor

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 -> {
Copy link
Contributor

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);
Copy link
Contributor

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

@imbajin imbajin force-pushed the support-update-strategy branch 2 times, most recently from 1f2ff21 to be2b8b3 Compare May 15, 2019 16:24
Iterator<Edge> oldEdges = g.edges(ids.toArray());
oldEdges.forEachRemaining(oldEdge -> {
updateExistElement(oldEdge,
maps.get(oldEdge.id().toString()),
Copy link
Contributor

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>?

Copy link
Member Author

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?

Copy link
Contributor

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}",
Copy link
Contributor

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 " +
Copy link
Contributor

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) {
Copy link
Contributor

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));
Copy link
Contributor

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) {
Copy link
Contributor

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 " +
Copy link
Contributor

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Iterator<Edge> oldEdges = g.edges(ids.toArray());
oldEdges.forEachRemaining(oldEdge -> {
updateExistElement(oldEdge,
maps.get(oldEdge.id().toString()),
Copy link
Contributor

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 " +
Copy link
Contributor

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,
Copy link
Contributor

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).
Copy link
Contributor

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) {
Copy link
Contributor

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) {
Copy link
Contributor

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();
Copy link
Contributor

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 :
Copy link
Contributor

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?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems unused TODO

Copy link
Member Author

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)
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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,
Copy link
Contributor

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);
Copy link
Contributor

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);

}

// TODO: Combine multi update methond into one (Element & JsonElement)
protected void updateExistElement(HugeGraph graph,
Copy link
Contributor

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();
Copy link
Contributor

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).
Copy link
Contributor

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),
Copy link
Contributor

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();
Copy link
Contributor

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()),
Copy link
Contributor

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());
Copy link
Contributor

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) {
Copy link
Contributor

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")
Copy link
Contributor

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) {
Copy link
Contributor

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.

@javeme
Copy link
Contributor

javeme commented May 24, 2019

Ugh, seems CI failed, please fix https://travis-ci.org/hugegraph/hugegraph/jobs/536220267
image

Copy link
Contributor

@Linary Linary left a 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);
Copy link
Contributor

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 {
Copy link
Contributor

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)
Copy link
Contributor

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) :
Copy link
Contributor

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) {
Copy link
Contributor

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) {
Copy link
Contributor

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) {
Copy link
Contributor

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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map or edges

Copy link
Contributor

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());
Copy link
Contributor

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 &&
Copy link
Contributor

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);
Copy link
Contributor

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",
Copy link
Contributor

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 ) {
Copy link
Contributor

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());
Copy link
Contributor

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);
Copy link
Contributor

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
Copy link
Contributor

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,
Copy link
Contributor

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unused TODO?

}
}

private static class JsonVertex extends JsonElement {
Copy link
Contributor

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 ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remember to modify these:

  1. hugegraph-api pom.xml <Implementation-Version>0.39.0.0</Implementation-Version> to <Implementation-Version>0.40.0.0</Implementation-Version>
  2. hugegraph-api ApiVersion.class 0.39 to 0.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.
@@ -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
Copy link
Contributor

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 {
Copy link
Contributor

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 {
Copy link
Contributor

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) {
Copy link
Contributor

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?
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Linary any suggestion?

Copy link
Contributor

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;
Copy link
Contributor

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

Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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);
Copy link
Contributor

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" })
Copy link
Contributor

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" })
Copy link
Contributor

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
* */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra *

Collection<? extends Checkable> bodys) {
E.checkArgumentNotNull(bodys, "The request body can't be empty");
for (Checkable body : bodys) {
E.checkArgumentNotNull(body,
Copy link
Contributor

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
**/
Copy link
Contributor

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
**/
Copy link
Contributor

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,
Copy link
Contributor

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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.checkArgument

Copy link
Contributor

@javeme javeme left a 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");
Copy link
Contributor

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, " +
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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");
Copy link
Contributor

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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dose not support

javeme
javeme previously approved these changes Jul 22, 2019
Linary
Linary previously approved these changes Jul 22, 2019
Object sortKeyValue = newEdge.properties.get(sortKey);
E.checkArgument(sortKeyValue != null,
"The value of sort key '%s' can't be null",
skId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

skId->sortKey


private static String formatError(Object oldProperty, Object newProperty,
String className) {
return String.format("Property must be %s, but got %s, %s", className,
Copy link
Contributor

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

Copy link
Member Author

@imbajin imbajin Jul 22, 2019

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

Copy link
Contributor

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.

Copy link
Member Author

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.

@imbajin imbajin dismissed stale reviews from Linary and javeme via 771ad3f July 23, 2019 03:44
formatError(oldProperty, newProperty,
"Set or List"));
this.formatError(oldProperty, newProperty,
this, "Set or List"));
Copy link
Contributor

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,
Copy link
Contributor

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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep private static

zhoney
zhoney previously approved these changes Jul 23, 2019
@javeme javeme merged commit 3fcfce2 into apache:master Jul 23, 2019
@gwny gwny mentioned this pull request Nov 20, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants