Skip to content

Commit

Permalink
feat(api): Support adamic-adar & resource-allocation algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
imbajin committed Jan 25, 2022
1 parent cadeade commit 8bfe4d5
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

public class API {

private static final Logger LOG = Log.logger(RestServer.class);
public static final Logger LOG = Log.logger(RestServer.class);

public static final String CHARSET = "UTF-8";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2022 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package com.baidu.hugegraph.api.traversers;

import static com.baidu.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_ELEMENTS_LIMIT;
import static com.baidu.hugegraph.traversal.algorithm.HugeTraverser.DEFAULT_MAX_DEGREE;

import javax.inject.Singleton;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;

import com.baidu.hugegraph.HugeGraph;
import com.baidu.hugegraph.api.API;
import com.baidu.hugegraph.api.graph.EdgeAPI;
import com.baidu.hugegraph.api.graph.VertexAPI;
import com.baidu.hugegraph.backend.id.Id;
import com.baidu.hugegraph.core.GraphManager;
import com.baidu.hugegraph.traversal.algorithm.PredictionTraverser;
import com.baidu.hugegraph.type.define.Directions;
import com.baidu.hugegraph.util.E;
import com.baidu.hugegraph.util.JsonUtil;
import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;

/**
* This API include similar prediction algorithms, now include:
* - Adamic Adar
* - Resource Allocation
*
* Could add more prediction algorithms in future
*/
@Path("graphs/{graph}/traversers/")
@Singleton
public class PredictionAPI extends API {

@GET
@Timed
@Path("adamicadar")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String get(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("vertex") String current,
@QueryParam("other") String other,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("limit")
@DefaultValue(DEFAULT_ELEMENTS_LIMIT) long limit) {
LOG.debug("Graph [{}] get adamic adar between '{}' and '{}' with " +
"direction {}, edge label {}, max degree '{}' and limit '{}'",
graph, current, other, direction, edgeLabel, maxDegree,
limit);

Id sourceId = VertexAPI.checkAndParseVertexId(current);
Id targetId = VertexAPI.checkAndParseVertexId(other);
E.checkArgument(!current.equals(other),
"The source and target vertex id can't be same");
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));

HugeGraph g = graph(manager, graph);
PredictionTraverser traverser = new PredictionTraverser(g);
double score = traverser.adamicAdar(sourceId, targetId, dir,
edgeLabel, maxDegree, limit);
return JsonUtil.toJson(ImmutableMap.of("adamic_adar", score));
}

@GET
@Timed
@Path("resourceallocation")
@Produces(APPLICATION_JSON_WITH_CHARSET)
public String create(@Context GraphManager manager,
@PathParam("graph") String graph,
@QueryParam("vertex") String current,
@QueryParam("other") String other,
@QueryParam("direction") String direction,
@QueryParam("label") String edgeLabel,
@QueryParam("max_degree")
@DefaultValue(DEFAULT_MAX_DEGREE) long maxDegree,
@QueryParam("limit")
@DefaultValue(DEFAULT_ELEMENTS_LIMIT) long limit) {
LOG.debug("Graph [{}] get resource allocation between '{}' and '{}' " +
"with direction {}, edge label {}, max degree '{}' and " +
"limit '{}'", graph, current, other, direction, edgeLabel,
maxDegree, limit);

Id sourceId = VertexAPI.checkAndParseVertexId(current);
Id targetId = VertexAPI.checkAndParseVertexId(other);
E.checkArgument(!current.equals(other),
"The source and target vertex id can't be same");
Directions dir = Directions.convert(EdgeAPI.parseDirection(direction));

HugeGraph g = graph(manager, graph);
PredictionTraverser traverser = new PredictionTraverser(g);
double score = traverser.resourceAllocation(sourceId, targetId, dir,
edgeLabel, maxDegree,
limit);
return JsonUtil.toJson(ImmutableMap.of("resource_allocation", score));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,13 @@ public final class ApiVersion {
* [0.65] Issue-1506: Support olap property key
* [0.66] Issue-1567: Support get schema RESTful API
* [0.67] Issue-1065: Support dynamically add/remove graph
* [0.68] Issue-1741: Support adamic-adar & resource-allocation API
*/

// The second parameter of Version.of() is for IDE running without JAR
public static final Version VERSION = Version.of(ApiVersion.class, "0.67");
public static final Version VERSION = Version.of(ApiVersion.class, "0.68");

public static final void check() {
public static void check() {
// Check version of hugegraph-core. Firstly do check from version 0.3
VersionUtil.check(CoreVersion.VERSION, "0.12", "0.13", CoreVersion.NAME);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/

package com.baidu.hugegraph.traversal.algorithm;

import static java.lang.Math.log;

import java.util.Set;

import com.baidu.hugegraph.HugeGraph;
import com.baidu.hugegraph.backend.id.Id;
import com.baidu.hugegraph.traversal.algorithm.steps.EdgeStep;
import com.baidu.hugegraph.type.define.Directions;
import com.baidu.hugegraph.util.E;
import com.google.common.collect.ImmutableList;

public class PredictionTraverser extends OltpTraverser {

public PredictionTraverser(HugeGraph graph) {
super(graph);
}

public double adamicAdar(Id source, Id target, Directions dir,
String label, long degree, long limit) {
Set<Id> neighbors = checkAndGetCommonNeighbors(source, target, dir,
label, degree, limit);
EdgeStep step = label == null ? new EdgeStep(graph(), dir) :
new EdgeStep(graph(), dir, ImmutableList.of(label));

return neighbors.stream()
.mapToDouble(vid -> 1.0 / log(edgesCount(vid, step)))
.sum();
}

public double resourceAllocation(Id source, Id target, Directions dir,
String label, long degree, long limit) {
Set<Id> neighbors = checkAndGetCommonNeighbors(source, target, dir,
label, degree, limit);
EdgeStep step = label == null ? new EdgeStep(graph(), dir) :
new EdgeStep(graph(), dir, ImmutableList.of(label));

return neighbors.stream()
.mapToDouble(vid -> 1.0 / edgesCount(vid, step))
.sum();
}

private Set<Id> checkAndGetCommonNeighbors(Id source, Id target,
Directions dir, String label,
long degree, long limit) {
E.checkNotNull(source, "source id");
E.checkNotNull(target, "the target id");
this.checkVertexExist(source, "source");
this.checkVertexExist(target, "target");
E.checkNotNull(dir, "direction");
checkDegree(degree);
SameNeighborTraverser traverser = new SameNeighborTraverser(graph());
return traverser.sameNeighbors(source, target, dir, label, degree, limit);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public EdgeStep(HugeGraph g, Directions direction, List<String> labels,
public EdgeStep(HugeGraph g, Directions direction, List<String> labels,
Map<String, Object> properties,
long degree, long skipDegree) {
E.checkNotNull(g, "The graph can't be null");
E.checkArgument(degree == NO_LIMIT || degree > 0L,
"The max degree must be > 0 or == -1, but got: %s",
degree);
Expand Down

0 comments on commit 8bfe4d5

Please sign in to comment.