├── kafka-graphs-rest-app ├── lombok.config ├── src │ ├── main │ │ ├── resources │ │ │ ├── banner.txt │ │ │ └── application.yml │ │ └── java │ │ │ └── io │ │ │ └── kgraph │ │ │ └── rest │ │ │ └── server │ │ │ ├── graph │ │ │ ├── GraphAlgorithmResultRequest.java │ │ │ ├── GraphAlgorithmRunRequest.java │ │ │ ├── GraphAlgorithmId.java │ │ │ ├── KeyValue.java │ │ │ ├── GraphAlgorithmCreateRequest.java │ │ │ ├── GroupEdgesBySourceRequest.java │ │ │ ├── GraphAlgorithmStatus.java │ │ │ └── GraphAlgorithmRouter.java │ │ │ ├── utils │ │ │ ├── VertexLongIdLongValueParser.java │ │ │ ├── EdgeLongIdLongValueParser.java │ │ │ ├── VertexLongIdDoubleValueParser.java │ │ │ └── EdgeLongIdDoubleValueParser.java │ │ │ ├── KafkaGraphsApplication.java │ │ │ ├── KafkaGraphsProperties.java │ │ │ ├── actuator │ │ │ ├── ZookeeperHealthIndicator.java │ │ │ └── KafkaHealthIndicator.java │ │ │ ├── curator │ │ │ └── CuratorConfiguration.java │ │ │ └── AppContextEventListener.java │ └── test │ │ ├── resources │ │ ├── vertices_simple.txt │ │ ├── edges_simple.txt │ │ ├── ratings_simple.txt │ │ └── application.yml │ │ └── java │ │ └── io │ │ └── kgraph │ │ └── rest │ │ └── server │ │ └── actuator │ │ └── ActuatorIntegrationTest.java ├── Dockerfile └── docker-compose.yml ├── .gitignore ├── kafka-graphs-core └── src │ ├── test │ ├── resources │ │ ├── vertices.txt │ │ ├── edges.txt │ │ ├── ratings_simple.txt │ │ └── logback.xml │ └── java │ │ └── io │ │ └── kgraph │ │ ├── pregel │ │ └── aggregators │ │ │ ├── EdgeCountToValue.java │ │ │ └── VertexCountToValue.java │ │ ├── streaming │ │ ├── summaries │ │ │ ├── DisjointSetTest.java │ │ │ └── AdjacencyListGraphTest.java │ │ └── library │ │ │ ├── ExactTriangleCountTest.java │ │ │ ├── SpannerTest.java │ │ │ ├── ConnectedComponentsTest.java │ │ │ └── BipartitenessCheckTest.java │ │ ├── AbstractIntegrationTest.java │ │ ├── JoinWithVerticesITCase.java │ │ └── utils │ │ └── TestUtils.java │ └── main │ └── java │ └── io │ └── kgraph │ ├── EdgeDirection.java │ ├── utils │ ├── Parser.java │ ├── KryoSerializer.java │ ├── KryoDeserializer.java │ ├── KryoSerde.java │ ├── TopicPartitionDeserializer.java │ ├── TopicPartitionSerializer.java │ ├── Parsers.java │ ├── KryoUtils.java │ └── GraphGenerators.java │ ├── EdgeJoinFunction.java │ ├── VertexJoinFunction.java │ ├── EdgesFunctionWithVertexValue.java │ ├── pregel │ ├── aggregators │ │ ├── Aggregator.java │ │ ├── LongSumAggregator.java │ │ ├── LongProductAggregator.java │ │ ├── DoubleSumAggregator.java │ │ ├── DoubleProductAggregator.java │ │ ├── BooleanAndAggregator.java │ │ ├── BooleanOrAggregator.java │ │ ├── LongMaxAggregator.java │ │ ├── LongMinAggregator.java │ │ ├── DoubleMinAggregator.java │ │ └── DoubleMaxAggregator.java │ ├── PregelStateDeserializer.java │ ├── PregelStateSerializer.java │ └── PregelClientSupplier.java │ ├── NeighborsFunctionWithVertexValue.java │ ├── library │ ├── cf │ │ ├── EdgeCfLongIdFloatValueParser.java │ │ ├── CfId.java │ │ ├── CfLongIdDeserializer.java │ │ ├── CfLongIdSerializer.java │ │ ├── CfLongIdSerde.java │ │ ├── FloatMatrixMessage.java │ │ └── CfLongId.java │ ├── basic │ │ ├── VertexCount.java │ │ ├── EdgeCount.java │ │ └── ReverseEdges.java │ ├── maxbmatching │ │ ├── MBMMessage.java │ │ └── MBMEdgeValue.java │ ├── clustering │ │ ├── DoubleListAggregator.java │ │ ├── KMeansVertexValue.java │ │ └── ListOfDoubleListAggregator.java │ ├── LabelPropagation.java │ ├── ConnectedComponents.java │ ├── BreadthFirstSearch.java │ ├── SingleSourceShortestPaths.java │ ├── MultipleSourceShortestPaths.java │ ├── PageRank.java │ └── GraphAlgorithmType.java │ ├── GraphAlgorithm.java │ ├── streaming │ ├── EdgeReduceFunction.java │ ├── EdgeFoldFunction.java │ ├── utils │ │ └── SignedVertex.java │ ├── library │ │ └── Spanner.java │ ├── SummaryAggregation.java │ └── KGraphWindowedStream.java │ ├── VertexWithValue.java │ ├── Edge.java │ ├── GraphSerialized.java │ ├── EdgeWithValue.java │ └── GraphAlgorithmState.java ├── .editorconfig ├── .github ├── workflows │ └── build.yml └── dependabot.yml └── findbugs-exclude.xml /kafka-graphs-rest-app/lombok.config: -------------------------------------------------------------------------------- 1 | lombok.anyConstructor.addConstructorProperties=true 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | lib_managed 4 | src_managed 5 | target 6 | *.ipr 7 | *.iws 8 | *.log 9 | *.swp 10 | .DS_Store 11 | dependency-reduced-pom.xml 12 | release.properties 13 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ╦╔═┌─┐┌─┐┬┌─┌─┐ ╔═╗┬─┐┌─┐┌─┐┬ ┬┌─┐ 2 | ╠╩╗├─┤├┤ ├┴┐├─┤ ║ ╦├┬┘├─┤├─┘├─┤└─┐ 3 | ╩ ╩┴ ┴└ ┴ ┴┴ ┴ ╚═╝┴└─┴ ┴┴ ┴ ┴└─┘ 4 | :: Welcome to Kafka Graphs! :: 5 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/resources/vertices.txt: -------------------------------------------------------------------------------- 1 | 0 0 2 | 1 1 3 | 2 2 4 | 3 3 5 | 4 4 6 | 5 5 7 | 6 6 8 | 7 7 9 | 8 8 10 | 9 9 11 | 10 10 12 | 11 11 13 | 12 12 14 | 13 13 15 | 14 14 16 | 15 15 17 | 16 16 18 | 17 17 19 | 18 18 20 | 19 19 21 | 20 20 22 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/test/resources/vertices_simple.txt: -------------------------------------------------------------------------------- 1 | 0 0 2 | 1 1 3 | 2 2 4 | 3 3 5 | 4 4 6 | 5 5 7 | 6 6 8 | 7 7 9 | 8 8 10 | 9 9 11 | 10 10 12 | 11 11 13 | 12 12 14 | 13 13 15 | 14 14 16 | 15 15 17 | 16 16 18 | 17 17 19 | 18 18 20 | 19 19 21 | 20 20 22 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/resources/edges.txt: -------------------------------------------------------------------------------- 1 | 0 1 1 2 | 1 2 1 3 | 2 3 1 4 | 3 4 1 5 | 4 5 1 6 | 5 6 1 7 | 6 7 1 8 | 7 8 1 9 | 8 9 1 10 | 10 11 1 11 | 11 12 1 12 | 12 13 1 13 | 13 14 1 14 | 14 15 1 15 | 15 16 1 16 | 16 17 1 17 | 17 18 1 18 | 18 19 1 19 | 19 20 1 20 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/test/resources/edges_simple.txt: -------------------------------------------------------------------------------- 1 | 0 1 1 2 | 1 2 1 3 | 2 3 1 4 | 3 4 1 5 | 4 5 1 6 | 5 6 1 7 | 6 7 1 8 | 7 8 1 9 | 8 9 1 10 | 10 11 1 11 | 11 12 1 12 | 12 13 1 13 | 13 14 1 14 | 14 15 1 15 | 15 16 1 16 | 16 17 1 17 | 17 18 1 18 | 18 19 1 19 | 19 20 1 20 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/resources/ratings_simple.txt: -------------------------------------------------------------------------------- 1 | 1 1 2 2 | 1 2 4 3 | 1 3 3.5 4 | 1 4 3 5 | 1 5 4 6 | 1 6 3.5 7 | 1 7 3.5 8 | 1 8 3 9 | 1 9 2.5 10 | 1 10 4 11 | 1 11 4 12 | 1 12 4 13 | 2 13 2 14 | 3 14 0.5 15 | 3 15 1 16 | 3 16 4 17 | 3 17 3 18 | 3 18 4 19 | 3 19 4 20 | 3 20 2.5 21 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/test/resources/ratings_simple.txt: -------------------------------------------------------------------------------- 1 | 1 1 2 2 | 1 2 4 3 | 1 3 3.5 4 | 1 4 3 5 | 1 5 4 6 | 1 6 3.5 7 | 1 7 3.5 8 | 1 8 3 9 | 1 9 2.5 10 | 1 10 4 11 | 1 11 4 12 | 1 12 4 13 | 2 13 2 14 | 3 14 0.5 15 | 3 15 1 16 | 3 16 4 17 | 3 17 3 18 | 3 18 4 19 | 3 19 4 20 | 3 20 2.5 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | indent_style = space 8 | 9 | [*.java] 10 | indent_style = space 11 | indent_size = 4 12 | 13 | [*.md] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | [*.xml] 18 | indent_style = space 19 | indent_size = 4 20 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM confluentinc/cp-base:latest 2 | 3 | ARG KAFKA_GRAPHS_VERSION 4 | ARG ARTIFACT_ID 5 | 6 | EXPOSE ${REST_APP_PORT} 7 | 8 | VOLUME /tmp 9 | ARG JAR_FILE=target/kafka-graphs-rest-app-${KAFKA_GRAPHS_VERSION}.jar 10 | COPY ${JAR_FILE} app.jar 11 | CMD ["/usr/bin/java", "-Dfile.encoding=UTF-8", "-Dserver.port=${REST_APP_PORT}", "-jar", "app.jar"] 12 | 13 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v2 11 | # For jblas, see https://github.com/mikiobraun/jblas/wiki/Missing-Libraries 12 | # May not be needed as jblas 1.2.5 bundles libgfortran4 13 | # See https://github.com/jblas-project/jblas/issues/87 14 | - name: Install jblas 15 | run: sudo apt-get install -y libgfortran5 16 | - name: Set up JDK 11 17 | uses: actions/setup-java@v2 18 | with: 19 | java-version: '11' 20 | distribution: 'adopt' 21 | - name: Build with Maven 22 | run: mvn -B package --file pom.xml 23 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | root: WARN 4 | org: 5 | spring: WARN 6 | io: 7 | kgraph: DEBUG 8 | 9 | info: 10 | app: 11 | name: Kafka Graphs 12 | 13 | kafka: 14 | graphs: 15 | bootstrapServers: ${BOOTSTRAP_SERVERS:localhost:9092} 16 | zookeeperConnect: ${ZOOKEEPER_CONNECT:localhost:2181} 17 | verticesTopic: vertices 18 | edgesGroupedBySourceTopic: edges 19 | solutionSetTopic: solutionSet 20 | solutionSetStore: solutionStore 21 | workSetTopic: workSet 22 | numPartitions: 50 23 | replicationFactor: 1 24 | 25 | management.endpoint.health.show-details: always 26 | management.endpoints.web.exposure.include: '*' 27 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | root: WARN 4 | org: 5 | spring: WARN 6 | io: 7 | kgraph: DEBUG 8 | 9 | info: 10 | app: 11 | name: Kafka Graphs Test 12 | 13 | kafka: 14 | graphs: 15 | bootstrapServers: ${spring.embedded.kafka.brokers} 16 | zookeeperConnect: ${spring.embedded.zookeeper.connect} 17 | verticesTopic: vertices 18 | edgesGroupedBySourceTopic: edges 19 | solutionSetTopic: solutionSet 20 | solutionSetStore: solutionStore 21 | workSetTopic: workSet 22 | numPartitions: 50 23 | replicationFactor: 1 24 | 25 | management.endpoint.health.show-details: always 26 | management.endpoints.web.exposure.include: '*' 27 | -------------------------------------------------------------------------------- /findbugs-exclude.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: maven 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | ignore: 9 | - dependency-name: com.github.spotbugs:spotbugs-maven-plugin 10 | versions: 11 | - 4.2.2 12 | - dependency-name: org.springframework.boot:spring-boot-dependencies 13 | versions: 14 | - 2.4.2 15 | - 2.4.3 16 | - 2.4.4 17 | - dependency-name: org.springframework:spring-test 18 | versions: 19 | - 5.3.3 20 | - 5.3.4 21 | - 5.3.5 22 | - dependency-name: io.projectreactor:reactor-test 23 | versions: 24 | - 3.4.2 25 | - 3.4.3 26 | - 3.4.4 27 | - dependency-name: com.esotericsoftware:kryo 28 | versions: 29 | - 5.0.3 30 | - 5.0.4 31 | - dependency-name: org.junit.jupiter:junit-jupiter-engine 32 | versions: 33 | - 5.7.0 34 | - dependency-name: org.junit.jupiter:junit-jupiter-api 35 | versions: 36 | - 5.7.0 37 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/EdgeDirection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | public enum EdgeDirection { 22 | IN, 23 | OUT, 24 | BOTH 25 | } 26 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/Parser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | @FunctionalInterface 22 | public interface Parser { 23 | T parse(String s); 24 | } 25 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/EdgeJoinFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | @FunctionalInterface 22 | public interface EdgeJoinFunction { 23 | 24 | EV joinEdges(EV edgeValue, T inputValue); 25 | } 26 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/VertexJoinFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | @FunctionalInterface 22 | public interface VertexJoinFunction { 23 | 24 | VV joinVertices(VV vertexValue, T inputValue); 25 | } 26 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/EdgesFunctionWithVertexValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | @FunctionalInterface 22 | public interface EdgesFunctionWithVertexValue { 23 | 24 | T iterateEdges(VV vertexValue, Iterable> edges); 25 | } 26 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/Aggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public interface Aggregator { 22 | 23 | void aggregate(T value); 24 | 25 | T getAggregate(); 26 | 27 | void setAggregate(T value); 28 | 29 | void reset(); 30 | } 31 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GraphAlgorithmResultRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import lombok.Getter; 22 | import lombok.Setter; 23 | 24 | @Getter 25 | @Setter 26 | public class GraphAlgorithmResultRequest { 27 | private String key; 28 | } 29 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GraphAlgorithmRunRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import lombok.Getter; 22 | import lombok.Setter; 23 | 24 | @Getter 25 | @Setter 26 | public class GraphAlgorithmRunRequest { 27 | private int numIterations = Integer.MAX_VALUE; 28 | } 29 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/NeighborsFunctionWithVertexValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.util.Map; 22 | 23 | @FunctionalInterface 24 | public interface NeighborsFunctionWithVertexValue { 25 | 26 | T iterateNeighbors(VV vertexValue, Map, VV> neighbors); 27 | } 28 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GraphAlgorithmId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.Setter; 24 | 25 | @AllArgsConstructor 26 | @Getter 27 | @Setter 28 | public class GraphAlgorithmId { 29 | private String id; 30 | } 31 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/KeyValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import lombok.AllArgsConstructor; 22 | import lombok.Getter; 23 | import lombok.Setter; 24 | 25 | @AllArgsConstructor 26 | @Getter 27 | @Setter 28 | public class KeyValue { 29 | private String key; 30 | private String value; 31 | } 32 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/utils/VertexLongIdLongValueParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.utils; 20 | 21 | import io.kgraph.utils.Parsers; 22 | 23 | public class VertexLongIdLongValueParser extends Parsers.VertexParser { 24 | public VertexLongIdLongValueParser() { 25 | super(Long::parseLong, Long::parseLong); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/utils/EdgeLongIdLongValueParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.utils; 20 | 21 | import io.kgraph.utils.Parsers; 22 | 23 | public class EdgeLongIdLongValueParser extends Parsers.EdgeParser { 24 | public EdgeLongIdLongValueParser() { 25 | super(Long::parseLong, Long::parseLong, Long::parseLong); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/utils/VertexLongIdDoubleValueParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.utils; 20 | 21 | import io.kgraph.utils.Parsers; 22 | 23 | public class VertexLongIdDoubleValueParser extends Parsers.VertexParser { 24 | public VertexLongIdDoubleValueParser() { 25 | super(Long::parseLong, Double::parseDouble); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/utils/EdgeLongIdDoubleValueParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.utils; 20 | 21 | import io.kgraph.utils.Parsers; 22 | 23 | public class EdgeLongIdDoubleValueParser extends Parsers.EdgeParser { 24 | public EdgeLongIdDoubleValueParser() { 25 | super(Long::parseLong, Long::parseLong, Double::parseDouble); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/KafkaGraphsApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server; 20 | 21 | import org.springframework.boot.SpringApplication; 22 | import org.springframework.boot.autoconfigure.SpringBootApplication; 23 | 24 | @SpringBootApplication 25 | public class KafkaGraphsApplication { 26 | public static void main(String[] args) { 27 | SpringApplication.run(KafkaGraphsApplication.class, args); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/KafkaGraphsProperties.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server; 20 | 21 | import org.springframework.boot.context.properties.ConfigurationProperties; 22 | 23 | import lombok.Getter; 24 | import lombok.Setter; 25 | 26 | @Getter 27 | @Setter 28 | @ConfigurationProperties(prefix = "kafka.graphs") 29 | public class KafkaGraphsProperties { 30 | private String bootstrapServers; 31 | private String zookeeperConnect; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/EdgeCfLongIdFloatValueParser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library.cf; 20 | 21 | import io.kgraph.utils.Parsers; 22 | 23 | public class EdgeCfLongIdFloatValueParser extends Parsers.EdgeParser { 24 | public EdgeCfLongIdFloatValueParser() { 25 | super(s -> new CfLongId((byte) 0, Long.parseLong(s)), 26 | s -> new CfLongId((byte) 1, Long.parseLong(s)), 27 | Float::parseFloat); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/KryoSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import java.util.Map; 22 | 23 | import org.apache.kafka.common.serialization.Serializer; 24 | 25 | public class KryoSerializer implements Serializer { 26 | @Override 27 | public void configure(Map map, boolean b) { 28 | } 29 | 30 | @Override 31 | public byte[] serialize(String s, T object) { 32 | if (object == null) { 33 | return null; 34 | } 35 | return KryoUtils.serialize(object); 36 | } 37 | 38 | @Override 39 | public void close() { 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/KryoDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import java.util.Map; 22 | 23 | import org.apache.kafka.common.serialization.Deserializer; 24 | 25 | public class KryoDeserializer implements Deserializer { 26 | @Override 27 | public void configure(Map map, boolean b) { 28 | } 29 | 30 | @Override 31 | public T deserialize(String s, byte[] bytes) { 32 | if (bytes == null) { 33 | return null; 34 | } 35 | return KryoUtils.deserialize(bytes); 36 | } 37 | 38 | @Override 39 | public void close() { 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/LongSumAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class LongSumAggregator implements Aggregator { 22 | 23 | private long value = 0; 24 | 25 | @Override 26 | public Long getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Long value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Long value) { 37 | this.value += value; 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = 0; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/LongProductAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class LongProductAggregator implements Aggregator { 22 | 23 | private long value = 1; 24 | 25 | @Override 26 | public Long getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Long value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Long value) { 37 | this.value *= value; 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = 1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/DoubleSumAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class DoubleSumAggregator implements Aggregator { 22 | 23 | private double value = 0; 24 | 25 | @Override 26 | public Double getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Double value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Double value) { 37 | this.value += value; 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = 0; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/DoubleProductAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class DoubleProductAggregator implements Aggregator { 22 | 23 | private double value = 1; 24 | 25 | @Override 26 | public Double getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Double value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Double value) { 37 | this.value *= value; 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = 1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GraphAlgorithmCreateRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import java.util.Map; 22 | 23 | import io.kgraph.library.GraphAlgorithmType; 24 | import lombok.Getter; 25 | import lombok.Setter; 26 | 27 | @Getter 28 | @Setter 29 | public class GraphAlgorithmCreateRequest { 30 | private GraphAlgorithmType algorithm; 31 | private Map configs; 32 | private String verticesTopic; 33 | private String edgesGroupedBySourceTopic; 34 | private int numPartitions = 50; 35 | private short replicationFactor = 1; 36 | private boolean valuesOfTypeDouble = false; 37 | } 38 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/BooleanAndAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class BooleanAndAggregator implements Aggregator { 22 | 23 | private boolean value = true; 24 | 25 | @Override 26 | public Boolean getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Boolean value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Boolean value) { 37 | this.value = this.value && value; 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/BooleanOrAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class BooleanOrAggregator implements Aggregator { 22 | 23 | private boolean value = false; 24 | 25 | @Override 26 | public Boolean getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Boolean value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Boolean value) { 37 | this.value = this.value || value; 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = false; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/LongMaxAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class LongMaxAggregator implements Aggregator { 22 | 23 | private long value = Long.MIN_VALUE; 24 | 25 | @Override 26 | public Long getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Long value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Long value) { 37 | this.value = Math.max(this.value, value); 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = Long.MIN_VALUE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/LongMinAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class LongMinAggregator implements Aggregator { 22 | 23 | private long value = Long.MAX_VALUE; 24 | 25 | @Override 26 | public Long getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Long value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Long value) { 37 | this.value = Math.min(this.value, value); 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = Long.MAX_VALUE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/DoubleMinAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class DoubleMinAggregator implements Aggregator { 22 | 23 | private double value = Double.MAX_VALUE; 24 | 25 | @Override 26 | public Double getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Double value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Double value) { 37 | this.value = Math.min(this.value, value); 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = Double.MAX_VALUE; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GroupEdgesBySourceRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import io.kgraph.library.GraphAlgorithmType; 22 | import lombok.Getter; 23 | import lombok.Setter; 24 | 25 | @Getter 26 | @Setter 27 | public class GroupEdgesBySourceRequest { 28 | private GraphAlgorithmType algorithm; 29 | private String initialVerticesTopic = null; 30 | private String initialEdgesTopic; 31 | private String verticesTopic; 32 | private String edgesGroupedBySourceTopic; 33 | private int numPartitions = 50; 34 | private short replicationFactor = 1; 35 | private boolean valuesOfTypeDouble = false; 36 | private boolean async = true; 37 | } 38 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/aggregators/DoubleMaxAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | public class DoubleMaxAggregator implements Aggregator { 22 | 23 | private double value = Double.NEGATIVE_INFINITY; 24 | 25 | @Override 26 | public Double getAggregate() { 27 | return value; 28 | } 29 | 30 | @Override 31 | public void setAggregate(Double value) { 32 | this.value = value; 33 | } 34 | 35 | @Override 36 | public void aggregate(Double value) { 37 | this.value = Math.max(this.value, value); 38 | } 39 | 40 | @Override 41 | public void reset() { 42 | value = Double.NEGATIVE_INFINITY; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/CfId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.cf; 17 | 18 | /** 19 | * Classes that implement this interface represent the ID of a node in a 20 | * user-item graph. Nodes in this case typically represent either users or items 21 | * and are identified by a number or a string (e.g. an item description). To 22 | * avoid conflicts between user and item ids, this interface defines the type 23 | * of the node as well, not just the identifier. The type is a byte value and 24 | * can by set and interpreted in an application-specific manner. 25 | * 26 | * @author dl 27 | * 28 | * @param the type of the id 29 | */ 30 | public interface CfId { 31 | /** 32 | * Returns the type of the node. 33 | * @return the type 34 | */ 35 | byte getType(); 36 | 37 | /** 38 | * Returns the identifier of the node. 39 | * @return the identifier 40 | */ 41 | T getId(); 42 | } 43 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/GraphAlgorithm.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.io.Closeable; 22 | import java.util.Map; 23 | import java.util.Properties; 24 | 25 | import org.apache.kafka.streams.KeyValue; 26 | import org.apache.kafka.streams.StreamsBuilder; 27 | 28 | public interface GraphAlgorithm extends Closeable { 29 | 30 | GraphAlgorithmState configure(StreamsBuilder builder, Properties streamsConfig); 31 | 32 | default GraphAlgorithmState run() { 33 | return run(Integer.MAX_VALUE); 34 | } 35 | 36 | GraphAlgorithmState run(int maxIterations); 37 | 38 | GraphAlgorithmState state(); 39 | 40 | Map configs(); 41 | 42 | Iterable> result(); 43 | } 44 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/CfLongIdDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library.cf; 20 | 21 | import java.nio.ByteBuffer; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.serialization.Deserializer; 25 | 26 | public class CfLongIdDeserializer implements Deserializer { 27 | @Override 28 | public void configure(Map map, boolean b) { 29 | } 30 | 31 | @Override 32 | public CfLongId deserialize(String topic, byte[] data) { 33 | if (data == null || data.length == 0) { 34 | return null; 35 | } 36 | ByteBuffer buf = ByteBuffer.wrap(data); 37 | byte type = buf.get(); 38 | long id = buf.getLong(); 39 | return new CfLongId(type, id); 40 | } 41 | 42 | @Override 43 | public void close() { 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/CfLongIdSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library.cf; 20 | 21 | import java.nio.ByteBuffer; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.serialization.Serializer; 25 | 26 | public class CfLongIdSerializer implements Serializer { 27 | 28 | private static final int TYPE_SIZE = 1; 29 | private static final int ID_SIZE = 8; 30 | 31 | @Override 32 | public void configure(Map map, boolean b) { 33 | } 34 | 35 | @Override 36 | public byte[] serialize(String topic, CfLongId id) { 37 | if (id == null) { 38 | return null; 39 | } 40 | ByteBuffer buf = ByteBuffer.allocate(TYPE_SIZE + ID_SIZE); 41 | buf.put(id.getType()); 42 | buf.putLong(id.getId()); 43 | return buf.array(); 44 | } 45 | 46 | @Override 47 | public void close() { 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/streaming/EdgeReduceFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming; 20 | 21 | /** 22 | * Interface to be implemented by the function applied to a vertex neighborhood 23 | * in the {@link KGraphWindowedStream#reduceOnEdges(EdgeReduceFunction)} method. 24 | * 25 | * @param the edge value type 26 | */ 27 | @FunctionalInterface 28 | public interface EdgeReduceFunction { 29 | 30 | /** 31 | * Combines two edge values into one value of the same type. 32 | * The reduceEdges function is consecutively applied to all pairs of edges of a neighborhood, 33 | * until only a single value remains. 34 | * 35 | * @param firstEdgeValue the value of the first edge 36 | * @param secondEdgeValue the value of the second edge 37 | * @return The data stream that is the result of applying the reduceEdges function to the graph window. 38 | */ 39 | EV reduceEdges(EV firstEdgeValue, EV secondEdgeValue); 40 | } 41 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/actuator/ZookeeperHealthIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.actuator; 20 | 21 | import org.apache.curator.framework.CuratorFramework; 22 | import org.springframework.boot.actuate.health.Health; 23 | import org.springframework.boot.actuate.health.ReactiveHealthIndicator; 24 | import org.springframework.stereotype.Component; 25 | 26 | import reactor.core.publisher.Mono; 27 | 28 | @Component 29 | public class ZookeeperHealthIndicator implements ReactiveHealthIndicator { 30 | 31 | private final CuratorFramework curator; 32 | 33 | public ZookeeperHealthIndicator(CuratorFramework curator) { 34 | this.curator = curator; 35 | } 36 | 37 | @Override 38 | public Mono health() { 39 | Health.Builder builder = new Health.Builder(); 40 | if (curator.getZookeeperClient().isConnected()) { 41 | builder.up(); 42 | } else { 43 | builder.down(); 44 | } 45 | return Mono.just(builder.build()); 46 | } 47 | } -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/VertexWithValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.util.Objects; 22 | 23 | public class VertexWithValue { 24 | 25 | private final K id; 26 | private final V value; 27 | 28 | public VertexWithValue(K id, V value) { 29 | this.id = id; 30 | this.value = value; 31 | } 32 | 33 | public K id() { 34 | return id; 35 | } 36 | 37 | public V value() { 38 | return value; 39 | } 40 | 41 | public String toString() { 42 | return "Vertex{id=" + id + ",val=" + value + "}"; 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | VertexWithValue that = (VertexWithValue) o; 50 | return Objects.equals(id, that.id) && 51 | Objects.equals(value, that.value); 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Objects.hash(id, value); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/basic/VertexCount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library.basic; 20 | 21 | import java.util.Map; 22 | 23 | import io.kgraph.EdgeWithValue; 24 | import io.kgraph.VertexWithValue; 25 | import io.kgraph.pregel.ComputeFunction; 26 | import io.kgraph.pregel.aggregators.LongSumAggregator; 27 | 28 | public class VertexCount implements ComputeFunction { 29 | 30 | public static final String VERTEX_COUNT_AGGREGATOR = "vertex.count.aggregator"; 31 | 32 | @Override 33 | public void init(Map configs, InitCallback cb) { 34 | cb.registerAggregator(VERTEX_COUNT_AGGREGATOR, LongSumAggregator.class); 35 | } 36 | 37 | @Override 38 | public void compute( 39 | int superstep, 40 | VertexWithValue vertex, 41 | Iterable messages, 42 | Iterable> edges, 43 | Callback cb 44 | ) { 45 | 46 | if (superstep == 0) { 47 | cb.aggregate(VERTEX_COUNT_AGGREGATOR, 1L); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/maxbmatching/MBMMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.maxbmatching; 17 | 18 | import java.util.Objects; 19 | 20 | import io.kgraph.library.maxbmatching.MBMEdgeValue.State; 21 | 22 | public class MBMMessage { 23 | private final Long vertexID; 24 | private final State state; 25 | 26 | public MBMMessage() { 27 | this.vertexID = 0L; 28 | this.state = State.DEFAULT; 29 | } 30 | 31 | public MBMMessage(Long id, State proposed) { 32 | this.vertexID = id; 33 | this.state = proposed; 34 | } 35 | 36 | public Long getId() { 37 | return vertexID; 38 | } 39 | 40 | public State getState() { 41 | return state; 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | return "(" + vertexID + ", " + state + ")"; 47 | } 48 | 49 | @Override 50 | public boolean equals(Object o) { 51 | if (this == o) return true; 52 | if (o == null || getClass() != o.getClass()) return false; 53 | MBMMessage that = (MBMMessage) o; 54 | return Objects.equals(vertexID, that.vertexID) && 55 | state == that.state; 56 | } 57 | 58 | @Override 59 | public int hashCode() { 60 | return Objects.hash(vertexID, state); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/streaming/EdgeFoldFunction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming; 20 | 21 | /** 22 | * Interface to be implemented by the function applied to a vertex neighborhood 23 | * in the {@link KGraphWindowedStream#foldNeighbors(Object, EdgeFoldFunction)} method. 24 | * 25 | * @param the vertex ID type 26 | * @param the edge value type 27 | * @param the accumulator type 28 | */ 29 | @FunctionalInterface 30 | public interface EdgeFoldFunction { 31 | 32 | /** 33 | * Combines two edge values into one value of the same type. 34 | * The foldEdges function is consecutively applied to all edges of a neighborhood, 35 | * until only a single value remains. 36 | * 37 | * @param accum the initial value and accumulator 38 | * @param vertexID the vertex ID 39 | * @param neighborID the neighbor's ID 40 | * @param edgeValue the edge value 41 | * @return The data stream that is the result of applying the foldEdges function to the graph window. 42 | */ 43 | T foldEdges(T accum, K vertexID, K neighborID, EV edgeValue); 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GraphAlgorithmStatus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import java.util.Map; 22 | import java.util.stream.Collectors; 23 | 24 | import io.kgraph.GraphAlgorithmState; 25 | import io.kgraph.GraphAlgorithmState.State; 26 | import io.kgraph.pregel.PregelComputation; 27 | import lombok.AllArgsConstructor; 28 | import lombok.Getter; 29 | import lombok.Setter; 30 | 31 | @AllArgsConstructor 32 | @Getter 33 | @Setter 34 | public class GraphAlgorithmStatus { 35 | 36 | public GraphAlgorithmStatus(GraphAlgorithmState state) { 37 | this.state = state.state(); 38 | this.superstep = state.superstep(); 39 | this.runningTime = state.runningTime(); 40 | this.aggregates = state.aggregates().entrySet().stream() 41 | .filter(e -> !e.getKey().equals(PregelComputation.LAST_WRITTEN_OFFSETS)) 42 | .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); 43 | } 44 | 45 | private State state; 46 | private int superstep; 47 | private long runningTime; 48 | private Map aggregates; 49 | } 50 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/Edge.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.util.Objects; 22 | 23 | public class Edge { 24 | 25 | private final K source; 26 | private final K target; 27 | 28 | public Edge(K source, K target) { 29 | this.source = source; 30 | this.target = target; 31 | } 32 | 33 | public Edge reverse() { 34 | 35 | return new Edge<>(target(), source()); 36 | } 37 | 38 | public K source() { 39 | return source; 40 | } 41 | 42 | public K target() { 43 | return target; 44 | } 45 | 46 | public String toString() { 47 | return "Edge{src=" + source + ",tgt=" + target + "}"; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | Edge edge = (Edge) o; 55 | return Objects.equals(source, edge.source) && 56 | Objects.equals(target, edge.target); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(source, target); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/KryoSerde.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.kgraph.utils; 18 | 19 | import java.util.Map; 20 | 21 | import org.apache.kafka.common.serialization.Deserializer; 22 | import org.apache.kafka.common.serialization.Serde; 23 | import org.apache.kafka.common.serialization.Serializer; 24 | 25 | public class KryoSerde implements Serde { 26 | 27 | private final Serializer serializer; 28 | private final Deserializer deserializer; 29 | 30 | public KryoSerde() { 31 | this.serializer = new KryoSerializer<>(); 32 | this.deserializer = new KryoDeserializer<>(); 33 | } 34 | 35 | @Override 36 | public void configure(Map configs, boolean isKey) { 37 | serializer.configure(configs, isKey); 38 | deserializer.configure(configs, isKey); 39 | } 40 | 41 | @Override 42 | public void close() { 43 | serializer.close(); 44 | deserializer.close(); 45 | } 46 | 47 | @Override 48 | public Serializer serializer() { 49 | return serializer; 50 | } 51 | 52 | @Override 53 | public Deserializer deserializer() { 54 | return deserializer; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/PregelStateDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel; 20 | 21 | import java.nio.ByteBuffer; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.serialization.Deserializer; 25 | 26 | import io.kgraph.GraphAlgorithmState; 27 | 28 | public class PregelStateDeserializer implements Deserializer { 29 | 30 | public PregelStateDeserializer() { 31 | } 32 | 33 | @Override 34 | public void configure(Map configs, boolean isKey) { 35 | } 36 | 37 | @Override 38 | public PregelState deserialize(String topic, byte[] data) { 39 | if (data == null || data.length == 0) { 40 | return null; 41 | } 42 | ByteBuffer buf = ByteBuffer.wrap(data); 43 | short mode = buf.getShort(); 44 | int superstep = buf.getInt(); 45 | short stage = buf.getShort(); 46 | long startTime = buf.getLong(); 47 | long endTime = buf.getLong(); 48 | 49 | return new PregelState(GraphAlgorithmState.State.get(mode), superstep, PregelState.Stage.get(stage), 50 | startTime, endTime); 51 | } 52 | 53 | @Override 54 | public void close() { 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/CfLongIdSerde.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.kgraph.library.cf; 18 | 19 | import java.util.Map; 20 | 21 | import org.apache.kafka.common.serialization.Deserializer; 22 | import org.apache.kafka.common.serialization.Serde; 23 | import org.apache.kafka.common.serialization.Serializer; 24 | 25 | public class CfLongIdSerde implements Serde { 26 | 27 | private final CfLongIdSerializer serializer; 28 | private final CfLongIdDeserializer deserializer; 29 | 30 | public CfLongIdSerde() { 31 | this.serializer = new CfLongIdSerializer(); 32 | this.deserializer = new CfLongIdDeserializer(); 33 | } 34 | 35 | @Override 36 | public void configure(Map configs, boolean isKey) { 37 | serializer.configure(configs, isKey); 38 | deserializer.configure(configs, isKey); 39 | } 40 | 41 | @Override 42 | public void close() { 43 | serializer.close(); 44 | deserializer.close(); 45 | } 46 | 47 | @Override 48 | public Serializer serializer() { 49 | return serializer; 50 | } 51 | 52 | @Override 53 | public Deserializer deserializer() { 54 | return deserializer; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/basic/EdgeCount.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library.basic; 20 | 21 | import java.util.Map; 22 | 23 | import io.kgraph.EdgeWithValue; 24 | import io.kgraph.VertexWithValue; 25 | import io.kgraph.pregel.ComputeFunction; 26 | import io.kgraph.pregel.aggregators.LongSumAggregator; 27 | 28 | public class EdgeCount implements ComputeFunction { 29 | 30 | public static final String EDGE_COUNT_AGGREGATOR = "edge.count.aggregator"; 31 | 32 | @Override 33 | public final void init(Map configs, InitCallback cb) { 34 | cb.registerAggregator(EDGE_COUNT_AGGREGATOR, LongSumAggregator.class, true); 35 | } 36 | 37 | @Override 38 | public void compute( 39 | int superstep, 40 | VertexWithValue vertex, 41 | Iterable messages, 42 | Iterable> edges, 43 | Callback cb 44 | ) { 45 | if (superstep == 0) { 46 | long count = 0L; 47 | for (EdgeWithValue edge : edges) { 48 | count++; 49 | } 50 | cb.aggregate(EDGE_COUNT_AGGREGATOR, count); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/pregel/aggregators/EdgeCountToValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | import java.util.Map; 22 | 23 | import io.kgraph.EdgeWithValue; 24 | import io.kgraph.VertexWithValue; 25 | import io.kgraph.library.basic.EdgeCount; 26 | import io.kgraph.pregel.ComputeFunction; 27 | 28 | public class EdgeCountToValue implements ComputeFunction { 29 | 30 | @Override 31 | public void init(Map configs, InitCallback cb) { 32 | cb.registerAggregator(EdgeCount.EDGE_COUNT_AGGREGATOR, LongSumAggregator.class, true); 33 | } 34 | 35 | @Override 36 | public void compute( 37 | int superstep, 38 | VertexWithValue vertex, 39 | Iterable messages, 40 | Iterable> edges, 41 | Callback cb 42 | ) { 43 | 44 | if (superstep == 0) { 45 | new EdgeCount().compute(superstep, vertex, messages, edges, cb); 46 | } else { 47 | Long count = cb.getAggregatedValue(EdgeCount.EDGE_COUNT_AGGREGATOR); 48 | cb.setNewVertexValue(count); 49 | cb.voteToHalt(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/streaming/utils/SignedVertex.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming.utils; 20 | 21 | import java.util.Objects; 22 | 23 | public class SignedVertex { 24 | 25 | private final long vertex; 26 | private final boolean sign; 27 | 28 | public SignedVertex(long vertex, boolean sign) { 29 | this.vertex = vertex; 30 | this.sign = sign; 31 | } 32 | 33 | public long vertex() { 34 | return vertex; 35 | } 36 | 37 | public boolean sign() { 38 | return sign; 39 | } 40 | 41 | public SignedVertex reverse() { 42 | return new SignedVertex(vertex(), !sign()); 43 | } 44 | 45 | @Override 46 | public boolean equals(Object o) { 47 | if (this == o) return true; 48 | if (o == null || getClass() != o.getClass()) return false; 49 | SignedVertex that = (SignedVertex) o; 50 | return vertex == that.vertex && 51 | sign == that.sign; 52 | } 53 | 54 | @Override 55 | public int hashCode() { 56 | return Objects.hash(vertex, sign); 57 | } 58 | 59 | @Override 60 | public String toString() { 61 | return "(" + vertex + "," + sign + ")"; 62 | } 63 | } -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/test/java/io/kgraph/rest/server/actuator/ActuatorIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.actuator; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | 23 | import java.io.IOException; 24 | 25 | import org.junit.Test; 26 | import org.junit.runner.RunWith; 27 | import org.springframework.beans.factory.annotation.Autowired; 28 | import org.springframework.boot.test.context.SpringBootTest; 29 | import org.springframework.boot.test.web.client.TestRestTemplate; 30 | import org.springframework.http.HttpStatus; 31 | import org.springframework.http.ResponseEntity; 32 | import org.springframework.test.context.junit4.SpringRunner; 33 | 34 | import io.kgraph.rest.server.KafkaGraphsApplication; 35 | 36 | @RunWith(SpringRunner.class) 37 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = KafkaGraphsApplication.class) 38 | public class ActuatorIntegrationTest { 39 | 40 | @Autowired 41 | private TestRestTemplate restTemplate; 42 | 43 | @Test 44 | public void testGetInfo() throws IOException { 45 | final ResponseEntity responseEntity = this.restTemplate.getForEntity("/actuator/info", String.class); 46 | assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); 47 | } 48 | } -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/PregelStateSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel; 20 | 21 | import java.nio.ByteBuffer; 22 | import java.util.Map; 23 | 24 | import org.apache.kafka.common.serialization.Serializer; 25 | 26 | public class PregelStateSerializer implements Serializer { 27 | private static final int MODE_SIZE = 2; 28 | private static final int SUPERSTEP_SIZE = 4; 29 | private static final int STAGE_SIZE = 2; 30 | private static final int TIME_SIZE = 8; 31 | 32 | public PregelStateSerializer() { 33 | } 34 | 35 | @Override 36 | public void configure(Map configs, boolean isKey) { 37 | } 38 | 39 | @Override 40 | public byte[] serialize(String topic, PregelState data) { 41 | if (data == null) { 42 | return null; 43 | } 44 | ByteBuffer buf = ByteBuffer.allocate(MODE_SIZE + SUPERSTEP_SIZE + STAGE_SIZE + TIME_SIZE + TIME_SIZE); 45 | buf.putShort((short) data.state().code()); 46 | buf.putInt(data.superstep()); 47 | buf.putShort((short) data.stage().code()); 48 | buf.putLong(data.startTime()); 49 | buf.putLong(data.endTime()); 50 | return buf.array(); 51 | } 52 | 53 | @Override 54 | public void close() { 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/clustering/DoubleListAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.clustering; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | import io.kgraph.pregel.aggregators.Aggregator; 22 | 23 | public class DoubleListAggregator implements Aggregator> { 24 | 25 | private List value = new ArrayList<>(); 26 | 27 | @Override 28 | public List getAggregate() { 29 | return value; 30 | } 31 | 32 | @Override 33 | public void setAggregate(List value) { 34 | this.value = value; 35 | } 36 | 37 | @Override 38 | public void aggregate(List other) { 39 | List aggrValue = getAggregate(); 40 | if ( aggrValue.size() == 0 ) { 41 | // first-time creation 42 | aggrValue.addAll(other); 43 | setAggregate(aggrValue); 44 | } 45 | else if ( aggrValue.size() < other.size() ) { 46 | throw new IndexOutOfBoundsException("The value to be aggregated " + 47 | "cannot have larger size than the aggregator value"); 48 | } 49 | else { 50 | for ( int i = 0; i < other.size(); i ++ ) { 51 | Double element = aggrValue.get(i) + other.get(i); 52 | aggrValue.set(i, element); 53 | } 54 | setAggregate(aggrValue); 55 | } 56 | } 57 | 58 | @Override 59 | public void reset() { 60 | value = new ArrayList<>(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/clustering/KMeansVertexValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.clustering; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Objects; 21 | 22 | /** 23 | * The type of the vertex value in K-means 24 | * It stores the coordinates of the point 25 | * and the currently assigned cluster id 26 | * 27 | */ 28 | public class KMeansVertexValue { 29 | private final List pointCoordinates; 30 | private final int clusterId; 31 | 32 | public KMeansVertexValue(List coordinates, int id) { 33 | this.pointCoordinates = coordinates; 34 | this.clusterId = id; 35 | } 36 | 37 | public KMeansVertexValue() { 38 | this.pointCoordinates = new ArrayList<>(); 39 | this.clusterId = 0; 40 | } 41 | 42 | public List getPointCoordinates() { 43 | return this.pointCoordinates; 44 | } 45 | 46 | public int getClusterId() { 47 | return this.clusterId; 48 | } 49 | 50 | @Override 51 | public boolean equals(Object o) { 52 | if (this == o) return true; 53 | if (o == null || getClass() != o.getClass()) return false; 54 | KMeansVertexValue that = (KMeansVertexValue) o; 55 | return clusterId == that.clusterId && 56 | Objects.equals(pointCoordinates, that.pointCoordinates); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(pointCoordinates, clusterId); 62 | } 63 | 64 | @Override 65 | public String toString() { 66 | return String.valueOf(this.clusterId); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/GraphSerialized.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.kgraph; 18 | 19 | import org.apache.kafka.common.serialization.Serde; 20 | 21 | public class GraphSerialized { 22 | 23 | private final Serde keySerde; 24 | private final Serde vertexValueSerde; 25 | private final Serde edgeValueSerde; 26 | 27 | private GraphSerialized(Serde keySerde, 28 | Serde vertexValueSerde, 29 | Serde edgeValueSerde) { 30 | this.keySerde = keySerde; 31 | this.vertexValueSerde = vertexValueSerde; 32 | this.edgeValueSerde = edgeValueSerde; 33 | } 34 | 35 | public Serde keySerde() { 36 | return keySerde; 37 | } 38 | 39 | public Serde vertexValueSerde() { 40 | return vertexValueSerde; 41 | } 42 | 43 | public Serde edgeValueSerde() { 44 | return edgeValueSerde; 45 | } 46 | 47 | protected GraphSerialized(GraphSerialized serialized) { 48 | this(serialized.keySerde, serialized.vertexValueSerde, serialized.edgeValueSerde); 49 | } 50 | 51 | public static GraphSerialized with(Serde keySerde, 52 | Serde vertexValueSerde, 53 | Serde edgeValueSerde) { 54 | return new GraphSerialized<>(keySerde, vertexValueSerde, edgeValueSerde); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/TopicPartitionDeserializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import java.io.UnsupportedEncodingException; 22 | import java.nio.ByteBuffer; 23 | import java.util.Map; 24 | 25 | import org.apache.kafka.common.TopicPartition; 26 | import org.apache.kafka.common.errors.SerializationException; 27 | import org.apache.kafka.common.serialization.Deserializer; 28 | 29 | public class TopicPartitionDeserializer implements Deserializer { 30 | private static final String ENCODING = "UTF8"; 31 | 32 | public TopicPartitionDeserializer() { 33 | } 34 | 35 | @Override 36 | public void configure(Map configs, boolean isKey) { 37 | } 38 | 39 | @Override 40 | public TopicPartition deserialize(String topic, byte[] data) { 41 | if (data == null || data.length == 0) { 42 | return null; 43 | } 44 | try { 45 | ByteBuffer buf = ByteBuffer.wrap(data); 46 | int topicLength = buf.getInt(); 47 | byte[] topicBytes = new byte[topicLength]; 48 | buf.get(topicBytes); 49 | String otherTopic = new String(topicBytes, ENCODING); 50 | int partition = buf.getInt(); 51 | 52 | return new TopicPartition(otherTopic, partition); 53 | } catch (UnsupportedEncodingException e) { 54 | throw new SerializationException("Error when deserializing byte[] to string"); 55 | } 56 | } 57 | 58 | @Override 59 | public void close() { 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/basic/ReverseEdges.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library.basic; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import io.kgraph.EdgeWithValue; 25 | import io.kgraph.VertexWithValue; 26 | import io.kgraph.pregel.ComputeFunction; 27 | 28 | public class ReverseEdges implements ComputeFunction> { 29 | private static final Logger log = LoggerFactory.getLogger(ReverseEdges.class); 30 | 31 | @Override 32 | public void compute( 33 | int superstep, 34 | VertexWithValue vertex, 35 | Iterable> messages, 36 | Iterable> edges, 37 | Callback> cb 38 | ) { 39 | if (superstep == 0) { 40 | for (EdgeWithValue edge : edges) { 41 | cb.sendMessageTo(edge.target(), edge); 42 | } 43 | } else if (superstep == 1) { 44 | for (EdgeWithValue msg : messages) { 45 | boolean hasEdge = false; 46 | for (EdgeWithValue edge : edges) { 47 | if (edge.target().equals(msg.source())) { 48 | hasEdge = true; 49 | break; 50 | } 51 | } 52 | if (!hasEdge) { 53 | cb.addEdge(msg.source(), msg.value()); 54 | } 55 | } 56 | } 57 | 58 | cb.voteToHalt(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/EdgeWithValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.util.Objects; 22 | 23 | public class EdgeWithValue { 24 | 25 | private final K source; 26 | private final K target; 27 | private final V value; 28 | 29 | public EdgeWithValue(Edge edge, V value) { 30 | this(edge.source(), edge.target(), value); 31 | } 32 | 33 | public EdgeWithValue(K source, K target, V value) { 34 | this.source = source; 35 | this.target = target; 36 | this.value = value; 37 | } 38 | 39 | public EdgeWithValue reverse() { 40 | 41 | return new EdgeWithValue<>(target(), source(), value()); 42 | } 43 | 44 | public K source() { 45 | return source; 46 | } 47 | 48 | public K target() { 49 | return target; 50 | } 51 | 52 | public V value() { 53 | return value; 54 | } 55 | 56 | public String toString() { 57 | return "Edge{src=" + source + ",tgt=" + target + ",val=" + value + "}"; 58 | } 59 | 60 | @Override 61 | public boolean equals(Object o) { 62 | if (this == o) return true; 63 | if (o == null || getClass() != o.getClass()) return false; 64 | EdgeWithValue that = (EdgeWithValue) o; 65 | return Objects.equals(source, that.source) && 66 | Objects.equals(target, that.target) && 67 | Objects.equals(value, that.value); 68 | } 69 | 70 | @Override 71 | public int hashCode() { 72 | return Objects.hash(source, target, value); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: '2' 3 | services: 4 | zookeeper: 5 | image: confluentinc/cp-zookeeper:5.4.0 6 | hostname: zookeeper 7 | ports: 8 | - '32181:32181' 9 | environment: 10 | ZOOKEEPER_CLIENT_PORT: 32181 11 | ZOOKEEPER_TICK_TIME: 2000 12 | extra_hosts: 13 | - "moby:127.0.0.1" 14 | 15 | kafka: 16 | image: confluentinc/cp-kafka:5.4.0 17 | hostname: kafka 18 | ports: 19 | - '9092:9092' 20 | - '29092:29092' 21 | depends_on: 22 | - zookeeper 23 | environment: 24 | KAFKA_BROKER_ID: 1 25 | KAFKA_ZOOKEEPER_CONNECT: zookeeper:32181 26 | KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 27 | KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT 28 | KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT 29 | KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 30 | extra_hosts: 31 | - "moby:127.0.0.1" 32 | 33 | # Runs the Kafka Graphs REST application 34 | kafka-graphs-rest-app-1: 35 | image: rayokota/kafka-graphs-rest-app:latest 36 | hostname: kafka-graphs-rest-app 37 | depends_on: 38 | - kafka 39 | - zookeeper 40 | command: "bash -c 'echo Waiting for Kafka to be ready... && \ 41 | cub zk-ready zookeeper:32181 20 && \ 42 | cub kafka-ready -b kafka:29092 1 20 && \ 43 | /usr/bin/java -Dfile.encoding=UTF-8 -Dserver.port=8888 -jar app.jar'" 44 | ports: 45 | - '8888:8888' 46 | environment: 47 | BOOTSTRAP_SERVERS: kafka:29092 48 | ZOOKEEPER_CONNECT: zookeeper:32181 49 | REST_APP_PORT: 8888 50 | extra_hosts: 51 | - "moby:127.0.0.1" 52 | 53 | kafka-graphs-rest-app-2: 54 | image: rayokota/kafka-graphs-rest-app:latest 55 | hostname: kafka-graphs-rest-app 56 | depends_on: 57 | - kafka 58 | - zookeeper 59 | command: "bash -c 'echo Waiting for Kafka to be ready... && \ 60 | cub zk-ready zookeeper:32181 20 && \ 61 | cub kafka-ready -b kafka:29092 1 20 && \ 62 | /usr/bin/java -Dfile.encoding=UTF-8 -Dserver.port=8889 -jar app.jar'" 63 | ports: 64 | - '8889:8889' 65 | environment: 66 | BOOTSTRAP_SERVERS: kafka:29092 67 | ZOOKEEPER_CONNECT: zookeeper:32181 68 | REST_APP_PORT: 8889 69 | extra_hosts: 70 | - "moby:127.0.0.1" 71 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/LabelPropagation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import java.util.Collections; 22 | import java.util.Map; 23 | import java.util.TreeMap; 24 | 25 | import io.kgraph.EdgeWithValue; 26 | import io.kgraph.VertexWithValue; 27 | import io.kgraph.pregel.ComputeFunction; 28 | 29 | public class LabelPropagation implements ComputeFunction> { 30 | 31 | @Override 32 | public void compute( 33 | int superstep, 34 | VertexWithValue vertex, 35 | Iterable> messages, 36 | Iterable> edges, 37 | Callback> cb) { 38 | 39 | Long vertexValue = vertex.value(); 40 | 41 | Map counts = new TreeMap<>(); 42 | for (Map message : messages) { 43 | message.forEach((k, v) -> counts.merge(k, v, (v1, v2) -> v1 + v2)); 44 | } 45 | if (!counts.isEmpty()) { 46 | Long maxKey = counts.entrySet().stream() 47 | .max((e1, e2) -> (int) (e1.getValue() - e2.getValue() != 0 48 | ? e1.getValue() - e2.getValue() : e1.getKey() - e2.getKey())).get().getKey(); 49 | 50 | if (vertexValue < maxKey) { 51 | vertexValue = maxKey; 52 | cb.setNewVertexValue(vertexValue); 53 | } 54 | } 55 | for (EdgeWithValue edge : edges) { 56 | cb.sendMessageTo(edge.target(), Collections.singletonMap(vertexValue, 1L)); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/TopicPartitionSerializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import java.io.UnsupportedEncodingException; 22 | import java.nio.ByteBuffer; 23 | import java.util.Map; 24 | 25 | import org.apache.kafka.common.TopicPartition; 26 | import org.apache.kafka.common.errors.SerializationException; 27 | import org.apache.kafka.common.serialization.Serializer; 28 | 29 | public class TopicPartitionSerializer implements Serializer { 30 | private static final String ENCODING = "UTF8"; 31 | private static final int ARRAY_LENGTH_SIZE = 4; 32 | private static final int PARTITION_SIZE = 4; 33 | 34 | public TopicPartitionSerializer() { 35 | } 36 | 37 | @Override 38 | public void configure(Map configs, boolean isKey) { 39 | } 40 | 41 | @Override 42 | public byte[] serialize(String topic, TopicPartition data) { 43 | if (data == null) { 44 | return null; 45 | } 46 | try { 47 | byte[] topicBytes = data.topic().getBytes(ENCODING); 48 | 49 | ByteBuffer buf = ByteBuffer.allocate(ARRAY_LENGTH_SIZE + topicBytes.length 50 | + PARTITION_SIZE); 51 | buf.putInt(topicBytes.length); 52 | buf.put(topicBytes); 53 | buf.putInt(data.partition()); 54 | return buf.array(); 55 | } catch (UnsupportedEncodingException e) { 56 | throw new SerializationException("Error when serializing string to byte[]"); 57 | } 58 | } 59 | 60 | @Override 61 | public void close() { 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/streaming/summaries/DisjointSetTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming.summaries; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertNotEquals; 23 | 24 | import java.util.HashSet; 25 | import java.util.Set; 26 | 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | 30 | 31 | public class DisjointSetTest { 32 | 33 | private final DisjointSet ds = new DisjointSet<>(); 34 | 35 | @Before 36 | public void setup() { 37 | for (int i = 0; i < 8; i++) { 38 | ds.union(i, i + 2); 39 | } 40 | } 41 | 42 | @Test 43 | public void testGetMatches() { 44 | assertEquals(ds.matches().size(), 10); 45 | } 46 | 47 | @Test 48 | public void testFind() { 49 | Integer root1 = ds.find(0); 50 | Integer root2 = ds.find(1); 51 | assertNotEquals(root1, root2); 52 | 53 | for (int i = 0; i < 10; i++) { 54 | assertEquals((i % 2) == 0 ? root1 : root2, ds.find(i)); 55 | } 56 | } 57 | 58 | @Test 59 | public void testMerge() { 60 | DisjointSet ds2 = new DisjointSet<>(); 61 | 62 | for (int i = 0; i < 8; i++) { 63 | ds2.union(i, i + 100); 64 | } 65 | 66 | ds2 = ds2.merge(ds); 67 | assertEquals(18, ds2.matches().size()); 68 | 69 | Set treeRoots = new HashSet<>(); 70 | 71 | for (int element : ds2.matches().keySet()) { 72 | treeRoots.add(ds2.find(element)); 73 | } 74 | 75 | assertEquals(2, treeRoots.size()); 76 | } 77 | } -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/graph/GraphAlgorithmRouter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.graph; 20 | 21 | import static org.springframework.web.reactive.function.server.RouterFunctions.route; 22 | 23 | import org.springframework.context.annotation.Bean; 24 | import org.springframework.context.annotation.Configuration; 25 | import org.springframework.web.reactive.function.server.RequestPredicates; 26 | import org.springframework.web.reactive.function.server.RouterFunction; 27 | import org.springframework.web.reactive.function.server.ServerResponse; 28 | 29 | @Configuration 30 | public class GraphAlgorithmRouter { 31 | 32 | @Bean 33 | protected RouterFunction routingFunction(GraphAlgorithmHandler graphAlgorithmHandler) { 34 | return route(RequestPredicates.POST("/import"), graphAlgorithmHandler::importGraph) 35 | .andRoute(RequestPredicates.POST("/prepare"), graphAlgorithmHandler::prepareGraph) 36 | .andRoute(RequestPredicates.POST("/pregel"), graphAlgorithmHandler::configure) 37 | .andRoute(RequestPredicates.POST("/pregel/{id}"), graphAlgorithmHandler::run) 38 | .andRoute(RequestPredicates.GET("/pregel/{id}"), graphAlgorithmHandler::state) 39 | .andRoute(RequestPredicates.GET("/pregel/{id}/configs"), graphAlgorithmHandler::configs) 40 | .andRoute(RequestPredicates.GET("/pregel/{id}/result"), graphAlgorithmHandler::result) 41 | .andRoute(RequestPredicates.POST("/pregel/{id}/result"), graphAlgorithmHandler::filterResult) 42 | .andRoute(RequestPredicates.DELETE("/pregel/{id}"), graphAlgorithmHandler::delete); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/FloatMatrixMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.cf; 17 | 18 | import java.util.Objects; 19 | 20 | import org.jblas.FloatMatrix; 21 | 22 | /** 23 | * Messages send in most of the CF algorithm typically must carry the id of the 24 | * message sender as well as the payload of the message, that is, the latent 25 | * vector. 26 | * @author dl 27 | * 28 | */ 29 | public class FloatMatrixMessage { 30 | private final CfLongId senderId; 31 | private final FloatMatrix factors; 32 | private final float score; 33 | 34 | public FloatMatrixMessage(FloatMatrixMessage msg) { 35 | this.senderId = msg.senderId; 36 | this.factors = msg.factors; 37 | this.score = msg.score; 38 | } 39 | 40 | public FloatMatrixMessage(CfLongId senderId, FloatMatrix factors, float score) { 41 | this.senderId = senderId; 42 | this.factors = factors; 43 | this.score = score; 44 | } 45 | 46 | public CfLongId getSenderId() { 47 | return senderId; 48 | } 49 | 50 | public FloatMatrix getFactors() { 51 | return factors; 52 | } 53 | 54 | public float getScore() { 55 | return score; 56 | } 57 | 58 | @Override 59 | public boolean equals(Object o) { 60 | if (this == o) return true; 61 | if (o == null || getClass() != o.getClass()) return false; 62 | FloatMatrixMessage that = (FloatMatrixMessage) o; 63 | return Float.compare(that.score, score) == 0 && 64 | Objects.equals(senderId, that.senderId) && 65 | Objects.equals(factors, that.factors); 66 | } 67 | 68 | @Override 69 | public int hashCode() { 70 | return Objects.hash(senderId, factors, score); 71 | } 72 | 73 | @Override 74 | public String toString() { 75 | return "[" + senderId + "] " + score + " " + factors; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/pregel/PregelClientSupplier.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.kgraph.pregel; 18 | 19 | import java.util.Map; 20 | 21 | import org.apache.kafka.clients.admin.Admin; 22 | import org.apache.kafka.clients.consumer.Consumer; 23 | import org.apache.kafka.clients.producer.Producer; 24 | import org.apache.kafka.streams.KafkaClientSupplier; 25 | import org.apache.kafka.streams.processor.internals.DefaultKafkaClientSupplier; 26 | 27 | public class PregelClientSupplier implements KafkaClientSupplier { 28 | 29 | private final DefaultKafkaClientSupplier defaultSupplier = new DefaultKafkaClientSupplier(); 30 | 31 | public PregelClientSupplier() { 32 | } 33 | 34 | @Override 35 | public Admin getAdmin(final Map config) { 36 | return defaultSupplier.getAdmin(config); 37 | } 38 | 39 | @Override 40 | public Producer getProducer(final Map config) { 41 | return defaultSupplier.getProducer(config); 42 | } 43 | 44 | @Override 45 | public Consumer getConsumer(final Map config) { 46 | Consumer consumer = new PregelConsumer(defaultSupplier.getConsumer(config)); 47 | return consumer; 48 | } 49 | 50 | @Override 51 | public Consumer getRestoreConsumer(final Map config) { 52 | return defaultSupplier.getRestoreConsumer(config); 53 | } 54 | 55 | @Override 56 | public Consumer getGlobalConsumer(final Map config) { 57 | Consumer consumer = new PregelConsumer(defaultSupplier.getGlobalConsumer(config)); 58 | return consumer; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/ConnectedComponents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | import io.kgraph.EdgeWithValue; 25 | import io.kgraph.VertexWithValue; 26 | import io.kgraph.pregel.ComputeFunction; 27 | 28 | public class ConnectedComponents implements ComputeFunction { 29 | private static final Logger log = LoggerFactory.getLogger(ConnectedComponents.class); 30 | 31 | @Override 32 | public void compute( 33 | int superstep, 34 | VertexWithValue vertex, 35 | Iterable messages, 36 | Iterable> edges, 37 | Callback cb) { 38 | 39 | Long currentValue = vertex.value(); 40 | 41 | for (Long message : messages) { 42 | currentValue = Math.min(currentValue, message); 43 | } 44 | 45 | if (currentValue < vertex.value()) { 46 | log.debug(">>> Vertex {} has new value {}", vertex.id(), currentValue); 47 | cb.setNewVertexValue(currentValue); 48 | } 49 | 50 | for (EdgeWithValue e : edges) { 51 | if (currentValue < e.target()) { 52 | log.debug(">>> Vertex {} sent to {} = {}", vertex.id(), e.target(), currentValue); 53 | cb.sendMessageTo(e.target(), currentValue); 54 | } else if (currentValue > e.target()) { 55 | log.debug(">>> Vertex {} sent to {} = {}", vertex.id(), currentValue, e.target()); 56 | cb.sendMessageTo(currentValue, e.target()); 57 | } 58 | } 59 | 60 | cb.voteToHalt(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/pregel/aggregators/VertexCountToValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.pregel.aggregators; 20 | 21 | import java.util.Map; 22 | 23 | import io.kgraph.EdgeWithValue; 24 | import io.kgraph.VertexWithValue; 25 | import io.kgraph.library.basic.VertexCount; 26 | import io.kgraph.pregel.ComputeFunction; 27 | 28 | public class VertexCountToValue implements ComputeFunction { 29 | 30 | @Override 31 | public void init(Map configs, InitCallback cb) { 32 | cb.registerAggregator(VertexCount.VERTEX_COUNT_AGGREGATOR, LongSumAggregator.class, true); 33 | } 34 | 35 | @Override 36 | public void preSuperstep(int superstep, Aggregators aggregators) { 37 | if (superstep == 0) { 38 | aggregators.aggregate(VertexCount.VERTEX_COUNT_AGGREGATOR, 10000L); 39 | } 40 | } 41 | 42 | @Override 43 | public void postSuperstep(int superstep, Aggregators aggregators) { 44 | if (superstep == 0) { 45 | aggregators.aggregate(VertexCount.VERTEX_COUNT_AGGREGATOR, 100000L); 46 | } 47 | } 48 | 49 | @Override 50 | public void compute( 51 | int superstep, 52 | VertexWithValue vertex, 53 | Iterable messages, 54 | Iterable> edges, 55 | Callback cb 56 | ) { 57 | 58 | if (superstep == 0) { 59 | new VertexCount().compute(superstep, vertex, messages, edges, cb); 60 | } else { 61 | Long count = cb.getAggregatedValue(VertexCount.VERTEX_COUNT_AGGREGATOR); 62 | cb.setNewVertexValue(count); 63 | cb.voteToHalt(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/actuator/KafkaHealthIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.actuator; 20 | 21 | import java.util.Properties; 22 | 23 | import org.apache.kafka.clients.admin.AdminClient; 24 | import org.apache.kafka.clients.admin.DescribeClusterOptions; 25 | import org.apache.kafka.clients.admin.DescribeClusterResult; 26 | import org.springframework.boot.actuate.health.Health; 27 | import org.springframework.boot.actuate.health.ReactiveHealthIndicator; 28 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 29 | import org.springframework.stereotype.Component; 30 | 31 | import io.kgraph.rest.server.KafkaGraphsProperties; 32 | import reactor.core.publisher.Mono; 33 | 34 | @Component 35 | @EnableConfigurationProperties(KafkaGraphsProperties.class) 36 | public class KafkaHealthIndicator implements ReactiveHealthIndicator { 37 | 38 | private final KafkaGraphsProperties props; 39 | 40 | public KafkaHealthIndicator(KafkaGraphsProperties props) { 41 | this.props = props; 42 | } 43 | 44 | @Override 45 | public Mono health() { 46 | Health.Builder builder = new Health.Builder(); 47 | Properties properties = new Properties(); 48 | properties.put("bootstrap.servers", props.getBootstrapServers()); 49 | try (AdminClient adminClient = AdminClient.create(properties)) { 50 | DescribeClusterResult result = adminClient.describeCluster(new DescribeClusterOptions().timeoutMs(3000)); 51 | builder.withDetail("clusterId", result.clusterId().get()); 52 | builder.up(); 53 | } catch (Exception e) { 54 | builder.down(); 55 | } 56 | return Mono.just(builder.build()); 57 | } 58 | } -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/curator/CuratorConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server.curator; 20 | 21 | import org.apache.curator.RetryPolicy; 22 | import org.apache.curator.framework.CuratorFramework; 23 | import org.apache.curator.framework.CuratorFrameworkFactory; 24 | import org.apache.curator.retry.ExponentialBackoffRetry; 25 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 26 | import org.springframework.context.annotation.Bean; 27 | import org.springframework.context.annotation.Configuration; 28 | 29 | import io.kgraph.rest.server.KafkaGraphsProperties; 30 | 31 | @Configuration 32 | @EnableConfigurationProperties(KafkaGraphsProperties.class) 33 | public class CuratorConfiguration { //implements BeanFactoryAware { 34 | 35 | private final KafkaGraphsProperties props; 36 | 37 | //private BeanFactory beanFactory; 38 | 39 | public CuratorConfiguration(KafkaGraphsProperties props) { 40 | this.props = props; 41 | } 42 | 43 | @Bean(initMethod = "start", destroyMethod = "close") 44 | public CuratorFramework curatorFramework(RetryPolicy retryPolicy) { 45 | 46 | final CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder(); 47 | builder 48 | .connectString(props.getZookeeperConnect()) 49 | .retryPolicy(retryPolicy); 50 | return builder.build(); 51 | } 52 | 53 | @Bean 54 | public RetryPolicy retryPolicy() { 55 | return new ExponentialBackoffRetry(1000, 3); 56 | //return new ExponentialBackoffRetry(props.getSleepTimeMs(), props.getMaxRetries()); 57 | } 58 | 59 | /* 60 | @Override 61 | public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 62 | this.beanFactory = beanFactory; 63 | } 64 | */ 65 | } 66 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/BreadthFirstSearch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import java.util.Map; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import io.kgraph.EdgeWithValue; 27 | import io.kgraph.VertexWithValue; 28 | import io.kgraph.pregel.ComputeFunction; 29 | 30 | /** 31 | * Adapted from the Graphalytics implementation. 32 | */ 33 | public final class BreadthFirstSearch implements ComputeFunction { 34 | private static final Logger log = LoggerFactory.getLogger(BreadthFirstSearch.class); 35 | 36 | public static final String SRC_VERTEX_ID = "srcVertexId"; 37 | public static final long UNVISITED = Long.MAX_VALUE; 38 | 39 | private long srcVertexId; 40 | 41 | @Override 42 | public void init(Map configs, InitCallback cb) { 43 | srcVertexId = (Long) configs.get(SRC_VERTEX_ID); 44 | } 45 | 46 | @Override 47 | public void compute( 48 | int superstep, 49 | VertexWithValue vertex, 50 | Iterable messages, 51 | Iterable> edges, 52 | Callback cb 53 | ) { 54 | 55 | if (superstep == 0) { 56 | if (vertex.id().equals(srcVertexId)) { 57 | cb.setNewVertexValue((long) superstep); 58 | for (EdgeWithValue edge : edges) { 59 | cb.sendMessageTo(edge.target(), (long) superstep); 60 | } 61 | } 62 | } else { 63 | if (vertex.value().equals(UNVISITED)) { 64 | cb.setNewVertexValue((long) superstep); 65 | for (EdgeWithValue edge : edges) { 66 | cb.sendMessageTo(edge.target(), (long) superstep); 67 | } 68 | } 69 | } 70 | 71 | cb.voteToHalt(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/SingleSourceShortestPaths.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import java.util.Map; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import io.kgraph.EdgeWithValue; 27 | import io.kgraph.VertexWithValue; 28 | import io.kgraph.pregel.ComputeFunction; 29 | 30 | public class SingleSourceShortestPaths implements ComputeFunction { 31 | private static final Logger log = LoggerFactory.getLogger(SingleSourceShortestPaths.class); 32 | 33 | public static final String SRC_VERTEX_ID = "srcVertexId"; 34 | 35 | private long srcVertexId; 36 | 37 | @Override 38 | public void init(Map configs, InitCallback cb) { 39 | srcVertexId = (Long) configs.get(SRC_VERTEX_ID); 40 | } 41 | 42 | @Override 43 | public void compute( 44 | int superstep, 45 | VertexWithValue vertex, 46 | Iterable messages, 47 | Iterable> edges, 48 | Callback cb) { 49 | 50 | double minDistance = (vertex.id().equals(srcVertexId)) ? 0d : Double.POSITIVE_INFINITY; 51 | 52 | for (Double message : messages) { 53 | minDistance = Math.min(minDistance, message); 54 | } 55 | 56 | log.debug(">>> Vertex {} got minDist = {} vertex value {}", vertex.id(), minDistance, vertex.value()); 57 | 58 | if (minDistance < vertex.value()) { 59 | cb.setNewVertexValue(minDistance); 60 | for (EdgeWithValue edge : edges) { 61 | double distance = minDistance + edge.value(); 62 | log.debug(">>> Vertex {} sent to {} = {}", vertex.id(), edge.target(), distance); 63 | cb.sendMessageTo(edge.target(), distance); 64 | } 65 | } 66 | 67 | cb.voteToHalt(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /kafka-graphs-rest-app/src/main/java/io/kgraph/rest/server/AppContextEventListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.rest.server; 20 | 21 | import java.util.ArrayList; 22 | import java.util.Collection; 23 | import java.util.List; 24 | 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | import org.springframework.context.event.ContextRefreshedEvent; 28 | import org.springframework.context.event.EventListener; 29 | import org.springframework.core.env.ConfigurableEnvironment; 30 | import org.springframework.core.env.MapPropertySource; 31 | import org.springframework.core.env.PropertySource; 32 | import org.springframework.stereotype.Component; 33 | 34 | @Component 35 | public class AppContextEventListener { 36 | private static final Logger log = LoggerFactory.getLogger(AppContextEventListener.class); 37 | 38 | @EventListener 39 | public void handleContextRefreshed(ContextRefreshedEvent event) { 40 | logActiveProperties((ConfigurableEnvironment) event.getApplicationContext().getEnvironment()); 41 | } 42 | 43 | private void logActiveProperties(ConfigurableEnvironment env) { 44 | List propertySources = new ArrayList<>(); 45 | 46 | for (PropertySource source : env.getPropertySources()) { 47 | if (source instanceof MapPropertySource && source.getName().contains("applicationConfig")) { 48 | propertySources.add((MapPropertySource) source); 49 | } 50 | } 51 | 52 | propertySources.stream() 53 | .map(propertySource -> propertySource.getSource().keySet()) 54 | .flatMap(Collection::stream) 55 | .distinct() 56 | .sorted() 57 | .forEach(key -> { 58 | try { 59 | log.debug(key + "=" + env.getProperty(key)); 60 | } catch (Exception e) { 61 | log.warn("{} -> {}", key, e.getMessage()); 62 | } 63 | }); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/clustering/ListOfDoubleListAggregator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.clustering; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import java.util.Map; 21 | import java.util.Random; 22 | 23 | import org.apache.kafka.common.Configurable; 24 | 25 | import io.kgraph.pregel.aggregators.Aggregator; 26 | 27 | public class ListOfDoubleListAggregator implements Aggregator>>, Configurable { 28 | 29 | public static final String CLUSTER_CENTERS_COUNT = "kmeans.cluster.centers.count"; 30 | public static final String POINTS_COUNT = "kmeans.points.count"; 31 | 32 | private int k; // the number of the cluster centers 33 | private int pointsCount; // the number of input points 34 | private List> value = new ArrayList<>(); 35 | 36 | @SuppressWarnings("unchecked") 37 | @Override 38 | public void configure(Map configs) { 39 | Map c = (Map) configs; 40 | k = (Integer) c.getOrDefault(CLUSTER_CENTERS_COUNT, 0); 41 | pointsCount = (Integer) c.getOrDefault(POINTS_COUNT, 0); 42 | } 43 | 44 | @Override 45 | public List> getAggregate() { 46 | return value; 47 | } 48 | 49 | @Override 50 | public void setAggregate(List> value) { 51 | this.value = value; 52 | } 53 | 54 | /** 55 | * Used to randomly select initial points for k-means 56 | * If the size of the current list is less than k (#centers) 57 | * then the element is appended in the list 58 | * else it replaces an element in a random position 59 | * with probability k/N, where N is the total number of points 60 | */ 61 | @Override 62 | public void aggregate(List> other) { 63 | for (List doubles : other) { 64 | if (getAggregate().size() < k) { 65 | value.add(doubles); 66 | } else { 67 | Random ran = new Random(0); 68 | int index = ran.nextInt(k); 69 | if (Math.random() > ((double) k / (double) pointsCount)) { 70 | value.set(index, doubles); 71 | } 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | public void reset() { 78 | value = new ArrayList<>(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/maxbmatching/MBMEdgeValue.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.maxbmatching; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | import java.util.Objects; 21 | 22 | public class MBMEdgeValue { 23 | private final double weight; 24 | private final State state; 25 | 26 | public MBMEdgeValue() { 27 | this(0, State.DEFAULT); 28 | } 29 | 30 | public MBMEdgeValue(double weight) { 31 | this(weight, State.DEFAULT); 32 | } 33 | 34 | public MBMEdgeValue(double weight, State state) { 35 | this.weight = weight; 36 | this.state = state; 37 | } 38 | 39 | public double getWeight() { 40 | return weight; 41 | } 42 | 43 | public State getState() { 44 | return state; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | return weight + "\t" + state; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object o) { 54 | if (this == o) return true; 55 | if (o == null || getClass() != o.getClass()) return false; 56 | MBMEdgeValue that = (MBMEdgeValue) o; 57 | return Double.compare(that.weight, weight) == 0 && 58 | state == that.state; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | return Objects.hash(weight, state); 64 | } 65 | 66 | public enum State { 67 | DEFAULT ((byte) 0), // starting state 68 | PROPOSED((byte) 1), // proposed for inclusion in the matching 69 | REMOVED ((byte) 2), // cannot be included in the matching 70 | INCLUDED((byte) 3); // included in the matching 71 | 72 | private final byte value; 73 | private static final Map lookup = new HashMap<>(); 74 | static { 75 | for (State s : values()) 76 | lookup.put(s.value, s); 77 | } 78 | 79 | State(byte value) { 80 | this.value = value; 81 | } 82 | 83 | public static State fromValue(byte value) { 84 | State result = lookup.get(value); 85 | if (result == null) 86 | throw new IllegalArgumentException("Cannot build edge State from illegal value: " + value); 87 | return result; 88 | } 89 | 90 | public byte value() { 91 | return value; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/AbstractIntegrationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.kgraph; 18 | 19 | import java.io.IOException; 20 | import java.util.Properties; 21 | import java.util.UUID; 22 | 23 | import org.apache.kafka.common.serialization.Serde; 24 | import org.apache.kafka.streams.KafkaStreams; 25 | import org.apache.kafka.streams.StreamsBuilder; 26 | import org.apache.kafka.streams.integration.utils.EmbeddedKafkaCluster; 27 | import org.apache.kafka.streams.integration.utils.IntegrationTestUtils; 28 | import org.junit.After; 29 | import org.junit.AfterClass; 30 | import org.junit.BeforeClass; 31 | 32 | import io.kgraph.utils.ClientUtils; 33 | 34 | public abstract class AbstractIntegrationTest { 35 | public static final EmbeddedKafkaCluster CLUSTER = new EmbeddedKafkaCluster(1, new Properties() {{ 36 | setProperty("message.max.bytes", String.valueOf(100 * 1024 * 1024)); 37 | }}); 38 | 39 | @BeforeClass 40 | public static void startCluster() throws IOException { 41 | CLUSTER.start(); 42 | } 43 | 44 | @AfterClass 45 | public static void closeCluster() { 46 | CLUSTER.stop(); 47 | } 48 | 49 | protected KafkaStreams streams; 50 | protected Properties streamsConfiguration; 51 | 52 | protected void startStreams(StreamsBuilder builder, Serde keySerde, Serde valueSerde) { 53 | String id = UUID.randomUUID().toString(); 54 | streamsConfiguration = ClientUtils.streamsConfig("test-" + id, "test-client-" + id, CLUSTER.bootstrapServers(), 55 | keySerde.getClass(), valueSerde.getClass()); 56 | streams = new KafkaStreams(builder.build(), streamsConfiguration); 57 | streams.start(); 58 | while (streams.state() != KafkaStreams.State.RUNNING) { 59 | try { 60 | Thread.sleep(1000); 61 | } catch (InterruptedException e) { 62 | // ignore 63 | } 64 | } 65 | } 66 | 67 | @After 68 | public void cleanup() throws Exception { 69 | if (streams != null) { 70 | streams.close(); 71 | } 72 | if (streamsConfiguration != null) { 73 | IntegrationTestUtils.purgeLocalStreamsState(streamsConfiguration); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/GraphAlgorithmState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.util.EnumSet; 22 | import java.util.HashMap; 23 | import java.util.Map; 24 | import java.util.concurrent.CompletableFuture; 25 | 26 | import org.apache.kafka.streams.KafkaStreams; 27 | 28 | public class GraphAlgorithmState { 29 | 30 | private final KafkaStreams streams; 31 | private final State state; 32 | private final long runningTime; 33 | private final Map aggregates; 34 | private final CompletableFuture result; 35 | private final int superstep; 36 | 37 | public GraphAlgorithmState(KafkaStreams streams, State state, int superstep, long runningTime, 38 | Map aggregates, CompletableFuture result) { 39 | this.streams = streams; 40 | this.state = state; 41 | this.superstep = superstep; 42 | this.runningTime = runningTime; 43 | this.aggregates = aggregates; 44 | this.result = result; 45 | } 46 | 47 | public KafkaStreams streams() { 48 | return streams; 49 | } 50 | 51 | public State state() { 52 | return state; 53 | } 54 | 55 | public long runningTime() { 56 | return runningTime; 57 | } 58 | 59 | public Map aggregates() { 60 | return aggregates; 61 | } 62 | 63 | public CompletableFuture result() { 64 | return result; 65 | } 66 | 67 | public int superstep() { 68 | return superstep; 69 | } 70 | 71 | public enum State { 72 | CREATED(0), 73 | RUNNING(1), 74 | COMPLETED(2), 75 | HALTED(3), 76 | ERROR(4); 77 | 78 | private static final Map lookup = new HashMap<>(); 79 | 80 | static { 81 | for (State m : EnumSet.allOf(State.class)) { 82 | lookup.put(m.code(), m); 83 | } 84 | } 85 | 86 | private final int code; 87 | 88 | State(int code) { 89 | this.code = code; 90 | } 91 | 92 | public int code() { 93 | return code; 94 | } 95 | 96 | public static State get(int code) { 97 | return lookup.get(code); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/streaming/library/ExactTriangleCountTest.java: -------------------------------------------------------------------------------- 1 | package io.kgraph.streaming.library; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Properties; 8 | import java.util.UUID; 9 | import java.util.stream.Collectors; 10 | 11 | import org.apache.kafka.common.serialization.LongSerializer; 12 | import org.apache.kafka.streams.KeyValue; 13 | import org.apache.kafka.streams.StreamsBuilder; 14 | import org.apache.kafka.streams.kstream.KStream; 15 | import org.apache.kafka.streams.kstream.KTable; 16 | import org.junit.Test; 17 | 18 | import io.kgraph.AbstractIntegrationTest; 19 | import io.kgraph.Edge; 20 | import io.kgraph.GraphSerialized; 21 | import io.kgraph.streaming.KGraphStream; 22 | import io.kgraph.streaming.EdgeStream; 23 | import io.kgraph.utils.ClientUtils; 24 | import io.kgraph.utils.KryoSerde; 25 | import io.kgraph.utils.StreamUtils; 26 | 27 | public class ExactTriangleCountTest extends AbstractIntegrationTest { 28 | 29 | @Test 30 | public void test() throws Exception { 31 | 32 | Properties producerConfig = ClientUtils.producerConfig(CLUSTER.bootstrapServers(), LongSerializer.class, 33 | LongSerializer.class, new Properties() 34 | ); 35 | StreamsBuilder builder = new StreamsBuilder(); 36 | 37 | int numPartitions = 1; 38 | KStream, Void> edges = StreamUtils.streamFromCollection(builder, producerConfig, 39 | "temp-" + UUID.randomUUID(), numPartitions, (short) 1, new KryoSerde<>(), new KryoSerde<>(), getEdges() 40 | ); 41 | KGraphStream graph = 42 | new EdgeStream<>(edges, GraphSerialized.with(new KryoSerde<>(), new KryoSerde<>(), new KryoSerde<>())); 43 | 44 | KTable result = ExactTriangleCount.countTriangles(graph); 45 | 46 | startStreams(builder, new KryoSerde<>(), new KryoSerde<>()); 47 | 48 | Thread.sleep(10000); 49 | 50 | List values = StreamUtils.listFromTable(streams, result).stream() 51 | .map(kv -> "(" + kv.key.toString() + "," + kv.value.toString() + ")") 52 | .sorted() 53 | .collect(Collectors.toList()); 54 | 55 | // This result will vary depending on the number of partitions 56 | assertEquals( 57 | "[(-1,4), (1,2), (2,2), (3,4), (4,1), (5,1), (6,2)]", 58 | values.toString() 59 | ); 60 | 61 | streams.close(); 62 | } 63 | 64 | static List, Void>> getEdges() { 65 | List, Void>> edges = new ArrayList<>(); 66 | edges.add(new KeyValue<>(new Edge<>(1L, 2L), null)); 67 | edges.add(new KeyValue<>(new Edge<>(2L, 3L), null)); 68 | edges.add(new KeyValue<>(new Edge<>(2L, 6L), null)); 69 | edges.add(new KeyValue<>(new Edge<>(5L, 6L), null)); 70 | edges.add(new KeyValue<>(new Edge<>(1L, 4L), null)); 71 | edges.add(new KeyValue<>(new Edge<>(5L, 3L), null)); 72 | edges.add(new KeyValue<>(new Edge<>(3L, 4L), null)); 73 | edges.add(new KeyValue<>(new Edge<>(3L, 6L), null)); 74 | edges.add(new KeyValue<>(new Edge<>(1L, 3L), null)); 75 | return edges; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/MultipleSourceShortestPaths.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import java.util.Map; 22 | import java.util.Set; 23 | import java.util.stream.Collectors; 24 | 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import io.kgraph.EdgeWithValue; 29 | import io.kgraph.VertexWithValue; 30 | import io.kgraph.pregel.ComputeFunction; 31 | 32 | public class MultipleSourceShortestPaths implements ComputeFunction, Double, Map> { 33 | private static final Logger log = LoggerFactory.getLogger(MultipleSourceShortestPaths.class); 34 | 35 | public static final String LANDMARK_VERTEX_IDS = "landmarkVertexIds"; 36 | 37 | private Set landmarkVertexIds; 38 | 39 | @Override 40 | @SuppressWarnings("unchecked") 41 | public void init(Map configs, InitCallback cb) { 42 | landmarkVertexIds = (Set) configs.get(LANDMARK_VERTEX_IDS); 43 | } 44 | 45 | @Override 46 | public void compute( 47 | int superstep, 48 | VertexWithValue> vertex, 49 | Iterable> messages, 50 | Iterable> edges, 51 | Callback, Double, Map> cb) { 52 | 53 | Map minDistance = landmarkVertexIds.stream().collect(Collectors.toMap(id -> id, 54 | id -> vertex.id().equals(id) ? 0d : Double.POSITIVE_INFINITY)); 55 | 56 | for (Map message : messages) { 57 | message.forEach((k, v) -> minDistance.merge(k, v, Math::min)); 58 | } 59 | vertex.value().forEach((k, v) -> minDistance.merge(k, v, Math::min)); 60 | 61 | log.debug(">>> Vertex {} got minDist = {} vertex value = {}", vertex.id(), minDistance, vertex.value()); 62 | 63 | if (!minDistance.equals(vertex.value())) { 64 | cb.setNewVertexValue(minDistance); 65 | for (EdgeWithValue edge : edges) { 66 | Map distance = minDistance.entrySet().stream() 67 | .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue() + edge.value())); 68 | log.debug(">>> Vertex {} sent to {} = {}", vertex.id(), edge.target(), distance); 69 | cb.sendMessageTo(edge.target(), distance); 70 | } 71 | } 72 | 73 | cb.voteToHalt(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/streaming/summaries/AdjacencyListGraphTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming.summaries; 20 | 21 | import static org.junit.Assert.assertEquals; 22 | import static org.junit.Assert.assertFalse; 23 | import static org.junit.Assert.assertTrue; 24 | 25 | import org.junit.Test; 26 | 27 | public class AdjacencyListGraphTest { 28 | 29 | @Test 30 | public void testAddEdge() { 31 | AdjacencyListGraph g = new AdjacencyListGraph<>(3); 32 | g.addEdge(1, 2); 33 | assertEquals(2, g.adjacencyMap().size()); 34 | assertTrue(g.adjacencyMap().get(1).contains(2)); 35 | assertTrue(g.adjacencyMap().get(2).contains(1)); 36 | assertEquals(1, g.adjacencyMap().get(1).size()); 37 | assertEquals(1, g.adjacencyMap().get(2).size()); 38 | 39 | g.addEdge(1, 3); 40 | assertEquals(3, g.adjacencyMap().size()); 41 | assertTrue(g.adjacencyMap().get(1).contains(2)); 42 | assertTrue(g.adjacencyMap().get(1).contains(3)); 43 | assertTrue(g.adjacencyMap().get(3).contains(1)); 44 | 45 | g.addEdge(3, 1); 46 | assertEquals(3, g.adjacencyMap().size()); 47 | assertEquals(2, g.adjacencyMap().get(1).size()); 48 | assertEquals(1, g.adjacencyMap().get(3).size()); 49 | 50 | g.addEdge(1, 2); 51 | assertEquals(3, g.adjacencyMap().size()); 52 | assertEquals(2, g.adjacencyMap().get(1).size()); 53 | assertEquals(1, g.adjacencyMap().get(2).size()); 54 | } 55 | 56 | @Test 57 | public void testBoundedBFS() { 58 | AdjacencyListGraph g = new AdjacencyListGraph<>(3); 59 | g.addEdge(1, 4); 60 | g.addEdge(4, 5); 61 | g.addEdge(5, 6); 62 | g.addEdge(4, 7); 63 | g.addEdge(7, 8); 64 | 65 | // check edge 2-3 (should be added) 66 | assertFalse(g.boundedBFS(2, 3)); 67 | g.addEdge(2, 3); 68 | 69 | // check edge 3-4 (should be added) 70 | assertFalse(g.boundedBFS(3, 4)); 71 | g.addEdge(3, 4); 72 | 73 | // check edge 3-6 (should be dropped) 74 | assertTrue(g.boundedBFS(3, 6)); 75 | 76 | // check edge 8-9 (should be added) 77 | assertFalse(g.boundedBFS(8, 9)); 78 | g.addEdge(8, 9); 79 | 80 | // check edge 8-6 (should be added) 81 | assertFalse(g.boundedBFS(8, 6)); 82 | g.addEdge(8, 6); 83 | 84 | // check edge 5-9 (should be dropped) 85 | assertTrue(g.boundedBFS(5, 9)); 86 | } 87 | } -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/cf/CfLongId.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Grafos.ml 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.kgraph.library.cf; 17 | 18 | import java.util.Objects; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | /** 23 | * This class represents the ID of a node in a CF scenario that has an 24 | * identifier of type long. 25 | * 26 | * @author dl 27 | * 28 | */ 29 | public class CfLongId implements CfId, Comparable> { 30 | 31 | private static final Pattern CF_LONG_ID_PATTERN = Pattern.compile("\\((\\d+),\\s*(\\d+)\\)"); 32 | 33 | private final byte type; 34 | private final Long id; 35 | 36 | public CfLongId(byte type, long id) { 37 | this.type = type; 38 | this.id = id; 39 | } 40 | 41 | public CfLongId(String s) { 42 | Matcher m = CF_LONG_ID_PATTERN.matcher(s); 43 | if (!m.matches()) { 44 | throw new IllegalArgumentException("Invalid string: " + s); 45 | } 46 | this.type = Byte.parseByte(m.group(2)); 47 | this.id = Long.parseLong(m.group(1)); 48 | } 49 | 50 | public boolean isItem() { 51 | return type == 1; 52 | } 53 | 54 | public boolean isUser() { 55 | return type == 0; 56 | } 57 | 58 | public boolean isOutput() { 59 | return type == -1; 60 | } 61 | 62 | public byte getType() { 63 | return type; 64 | } 65 | 66 | public Long getId() { 67 | return id; 68 | } 69 | 70 | @Override 71 | public int compareTo(CfId that) { 72 | if (this.type < that.getType()) { 73 | return -1; 74 | } else if (this.type > that.getType()) { 75 | return 1; 76 | } 77 | 78 | if (this.id.compareTo(that.getId()) < 0) { 79 | return -1; 80 | } else if (this.id.compareTo(that.getId()) > 0) { 81 | return 1; 82 | } 83 | return 0; 84 | } 85 | 86 | 87 | @Override 88 | public boolean equals(Object o) { 89 | if (this == o) return true; 90 | if (o == null || getClass() != o.getClass()) return false; 91 | CfLongId cfLongId = (CfLongId) o; 92 | return type == cfLongId.type && 93 | Objects.equals(id, cfLongId.id); 94 | } 95 | 96 | @Override 97 | public int hashCode() { 98 | final int prime = 31; 99 | int result = 1; 100 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 101 | result = prime * result + type; 102 | return result; 103 | } 104 | 105 | @Override 106 | public String toString() { 107 | return "(" + id + ", " + type + ")"; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/JoinWithVerticesITCase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph; 20 | 21 | import java.util.List; 22 | import java.util.Properties; 23 | 24 | import org.apache.kafka.common.serialization.LongSerializer; 25 | import org.apache.kafka.common.serialization.Serdes; 26 | import org.apache.kafka.streams.KeyValue; 27 | import org.apache.kafka.streams.StreamsBuilder; 28 | import org.apache.kafka.streams.kstream.KTable; 29 | import org.junit.Test; 30 | 31 | import io.kgraph.utils.ClientUtils; 32 | import io.kgraph.utils.KryoSerde; 33 | import io.kgraph.utils.StreamUtils; 34 | import io.kgraph.utils.TestUtils; 35 | 36 | public class JoinWithVerticesITCase extends AbstractIntegrationTest { 37 | 38 | private String expectedResult; 39 | 40 | @Test 41 | public void testJoinWithVertexSet() throws Exception { 42 | Properties producerConfig = ClientUtils.producerConfig(CLUSTER.bootstrapServers(), LongSerializer.class, 43 | LongSerializer.class, new Properties() 44 | ); 45 | StreamsBuilder builder = new StreamsBuilder(); 46 | 47 | KTable vertices = 48 | StreamUtils.tableFromCollection(builder, producerConfig, Serdes.Long(), Serdes.Long(), 49 | TestGraphUtils.getLongLongVertices()); 50 | 51 | KTable, Long> edges = 52 | StreamUtils.tableFromCollection(builder, producerConfig, new KryoSerde<>(), Serdes.Long(), 53 | TestGraphUtils.getLongLongEdges()); 54 | 55 | KGraph graph = new KGraph<>( 56 | vertices, edges, GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Long())); 57 | 58 | KGraph res = graph.joinWithVertices(graph.vertices() 59 | .mapValues(v -> v), new AddValuesMapper()); 60 | 61 | KTable data = res.vertices(); 62 | 63 | startStreams(builder, Serdes.Long(), Serdes.Long()); 64 | 65 | Thread.sleep(5000); 66 | 67 | List> result = StreamUtils.listFromTable(streams, data); 68 | 69 | expectedResult = "1,2\n" + 70 | "2,4\n" + 71 | "3,6\n" + 72 | "4,8\n" + 73 | "5,10\n"; 74 | 75 | TestUtils.compareResultAsTuples(result, expectedResult); 76 | } 77 | 78 | private static final class AddValuesMapper implements VertexJoinFunction { 79 | 80 | public Long joinVertices(Long vertexValue, Long inputValue) { 81 | return vertexValue + inputValue; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/streaming/library/Spanner.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming.library; 20 | 21 | import org.apache.kafka.streams.kstream.Reducer; 22 | 23 | import io.kgraph.streaming.EdgeFoldFunction; 24 | import io.kgraph.streaming.SummaryBulkAggregation; 25 | import io.kgraph.streaming.summaries.AdjacencyListGraph; 26 | 27 | /** 28 | * The Spanner library method continuously computes a k-Spanner of an insertion-only edge stream. 29 | * The user-defined parameter k defines the distance estimation error, 30 | * i.e. a k-spanner preserves all distances with a factor of up to k. 31 | *

32 | * This is a single-pass implementation, which uses a {@link SummaryBulkAggregation} to periodically merge 33 | * the partitioned state. 34 | * 35 | * @param the vertex ID type 36 | * @param the edge value type 37 | */ 38 | public class Spanner, EV> extends SummaryBulkAggregation, AdjacencyListGraph> { 39 | 40 | /** 41 | * Creates a Spanner instance. 42 | * 43 | * @param mergeWindowTime Window time in millisec for the merger. 44 | * @param k the distance error factor 45 | */ 46 | public Spanner(long mergeWindowTime, int k) { 47 | super(new UpdateLocal<>(), new CombineSpanners<>(), new AdjacencyListGraph<>(k), mergeWindowTime, false); 48 | } 49 | 50 | /** 51 | * Decide to add or remove an edge to the local spanner in the current window. 52 | * If the current distance between the edge endpoints is <= k then the edge is dropped, 53 | * otherwise it is added to the local spanner. 54 | * 55 | * @param the vertex ID type 56 | */ 57 | public static final class UpdateLocal, EV> implements EdgeFoldFunction> { 58 | 59 | public UpdateLocal() { 60 | } 61 | 62 | @Override 63 | public AdjacencyListGraph foldEdges(AdjacencyListGraph g, K src, K trg, EV value) { 64 | if (!g.boundedBFS(src, trg)) { 65 | // the current distance between src and trg is > k 66 | g = new AdjacencyListGraph<>(g, src, trg); 67 | } 68 | return g; 69 | } 70 | } 71 | 72 | /** 73 | * Merge the local spanners of each partition into the global spanner. 74 | */ 75 | public static class CombineSpanners> implements Reducer> { 76 | 77 | public CombineSpanners() { 78 | } 79 | 80 | @Override 81 | public AdjacencyListGraph apply(AdjacencyListGraph g1, AdjacencyListGraph g2) { 82 | return g1.size() <= g2.size() ? g2.merge(g1) : g1.merge(g2); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/streaming/library/SpannerTest.java: -------------------------------------------------------------------------------- 1 | package io.kgraph.streaming.library; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.Properties; 8 | import java.util.UUID; 9 | import java.util.stream.Collectors; 10 | 11 | import org.apache.kafka.common.serialization.LongSerializer; 12 | import org.apache.kafka.streams.KeyValue; 13 | import org.apache.kafka.streams.StreamsBuilder; 14 | import org.apache.kafka.streams.kstream.KStream; 15 | import org.apache.kafka.streams.kstream.KTable; 16 | import org.apache.kafka.streams.kstream.Windowed; 17 | import org.junit.Test; 18 | 19 | import io.kgraph.AbstractIntegrationTest; 20 | import io.kgraph.Edge; 21 | import io.kgraph.GraphSerialized; 22 | import io.kgraph.streaming.KGraphStream; 23 | import io.kgraph.streaming.EdgeStream; 24 | import io.kgraph.streaming.summaries.AdjacencyListGraph; 25 | import io.kgraph.utils.ClientUtils; 26 | import io.kgraph.utils.KryoSerde; 27 | import io.kgraph.utils.StreamUtils; 28 | 29 | public class SpannerTest extends AbstractIntegrationTest { 30 | 31 | private static final long mergeWindowTime = 1000; 32 | private static final int k = 3; 33 | 34 | @Test 35 | public void test() throws Exception { 36 | 37 | Properties producerConfig = ClientUtils.producerConfig(CLUSTER.bootstrapServers(), LongSerializer.class, 38 | LongSerializer.class, new Properties() 39 | ); 40 | StreamsBuilder builder = new StreamsBuilder(); 41 | 42 | // Use 1 partition for deterministic ordering 43 | int numPartitions = 1; 44 | KStream, Void> edges = StreamUtils.streamFromCollection(builder, producerConfig, 45 | "temp-" + UUID.randomUUID(), numPartitions, (short) 1, new KryoSerde<>(), new KryoSerde<>(), getEdges() 46 | ); 47 | KGraphStream graph = 48 | new EdgeStream<>(edges, GraphSerialized.with(new KryoSerde<>(), new KryoSerde<>(), new KryoSerde<>())); 49 | 50 | KTable, AdjacencyListGraph> sets = graph.aggregate(new Spanner<>(mergeWindowTime, k)); 51 | 52 | startStreams(builder, new KryoSerde<>(), new KryoSerde<>()); 53 | 54 | Thread.sleep(10000); 55 | 56 | List values = StreamUtils.listFromTable(streams, sets).stream() 57 | .map(kv -> kv.value.toString()) 58 | .sorted() 59 | .collect(Collectors.toList()); 60 | 61 | // This result will vary depending on the number of partitions 62 | assertEquals( 63 | "[{1=[4], 2=[3], 3=[2, 4], 4=[1, 3, 5, 7], 5=[4, 6], 6=[5, 8], 7=[4, 8], 8=[6, 7, 9], 9=[8]}]", 64 | values.toString() 65 | ); 66 | 67 | streams.close(); 68 | } 69 | 70 | static List, Void>> getEdges() { 71 | List, Void>> edges = new ArrayList<>(); 72 | edges.add(new KeyValue<>(new Edge<>(1L, 4L), null)); 73 | edges.add(new KeyValue<>(new Edge<>(4L, 7L), null)); 74 | edges.add(new KeyValue<>(new Edge<>(7L, 8L), null)); 75 | edges.add(new KeyValue<>(new Edge<>(4L, 8L), null)); 76 | edges.add(new KeyValue<>(new Edge<>(4L, 5L), null)); 77 | edges.add(new KeyValue<>(new Edge<>(5L, 6L), null)); 78 | edges.add(new KeyValue<>(new Edge<>(2L, 3L), null)); 79 | edges.add(new KeyValue<>(new Edge<>(3L, 4L), null)); 80 | edges.add(new KeyValue<>(new Edge<>(3L, 6L), null)); 81 | edges.add(new KeyValue<>(new Edge<>(8L, 9L), null)); 82 | edges.add(new KeyValue<>(new Edge<>(6L, 8L), null)); 83 | edges.add(new KeyValue<>(new Edge<>(5L, 9L), null)); 84 | return edges; 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/Parsers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import io.kgraph.EdgeWithValue; 22 | import io.kgraph.VertexWithValue; 23 | 24 | public class Parsers { 25 | 26 | public static final class IntegerParser implements Parser { 27 | @Override 28 | public Integer parse(String s) { 29 | return Integer.parseInt(s); 30 | } 31 | } 32 | 33 | public static final class LongParser implements Parser { 34 | @Override 35 | public Long parse(String s) { 36 | return Long.parseLong(s); 37 | } 38 | } 39 | 40 | public static final class FloatParser implements Parser { 41 | @Override 42 | public Float parse(String s) { 43 | return Float.parseFloat(s); 44 | } 45 | } 46 | 47 | public static final class DoubleParser implements Parser { 48 | @Override 49 | public Double parse(String s) { 50 | return Double.parseDouble(s); 51 | } 52 | } 53 | 54 | public static final class StringParser implements Parser { 55 | @Override 56 | public String parse(String s) { 57 | return s; 58 | } 59 | } 60 | 61 | public static class VertexParser implements Parser> { 62 | private final Parser idParser; 63 | private final Parser valueParser; 64 | public VertexParser(Parser idParser, Parser valueParser) { 65 | this.idParser = idParser; 66 | this.valueParser = valueParser; 67 | } 68 | @Override 69 | public VertexWithValue parse(String s) { 70 | String[] tokens = s.trim().split("\\s"); 71 | K id = idParser.parse(tokens[0]); 72 | V value = tokens.length > 1 ? valueParser.parse(tokens[1]) : null; 73 | return new VertexWithValue<>(id, value); 74 | } 75 | } 76 | 77 | public static class EdgeParser implements Parser> { 78 | private final Parser sourceIdParser; 79 | private final Parser targetIdParser; 80 | private final Parser valueParser; 81 | public EdgeParser(Parser sourceIdParser, Parser targetIdParser, Parser valueParser) { 82 | this.sourceIdParser = sourceIdParser; 83 | this.targetIdParser = targetIdParser; 84 | this.valueParser = valueParser; 85 | } 86 | @Override 87 | public EdgeWithValue parse(String s) { 88 | String[] tokens = s.trim().split("\\s"); 89 | K sourceId = sourceIdParser.parse(tokens[0]); 90 | K targetId = targetIdParser.parse(tokens[1]); 91 | V value = tokens.length > 2 ? valueParser.parse(tokens[2]) : null; 92 | return new EdgeWithValue<>(sourceId, targetId, value); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/streaming/library/ConnectedComponentsTest.java: -------------------------------------------------------------------------------- 1 | package io.kgraph.streaming.library; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.Properties; 9 | import java.util.stream.Collectors; 10 | 11 | import org.apache.kafka.common.serialization.LongSerializer; 12 | import org.apache.kafka.streams.KeyValue; 13 | import org.apache.kafka.streams.StreamsBuilder; 14 | import org.apache.kafka.streams.kstream.KStream; 15 | import org.apache.kafka.streams.kstream.KTable; 16 | import org.apache.kafka.streams.kstream.Windowed; 17 | import org.junit.Assert; 18 | import org.junit.Test; 19 | 20 | import io.kgraph.AbstractIntegrationTest; 21 | import io.kgraph.Edge; 22 | import io.kgraph.GraphSerialized; 23 | import io.kgraph.streaming.KGraphStream; 24 | import io.kgraph.streaming.EdgeStream; 25 | import io.kgraph.streaming.summaries.DisjointSet; 26 | import io.kgraph.utils.ClientUtils; 27 | import io.kgraph.utils.KryoSerde; 28 | import io.kgraph.utils.StreamUtils; 29 | 30 | public class ConnectedComponentsTest extends AbstractIntegrationTest { 31 | 32 | @Test 33 | public void test() throws Exception { 34 | 35 | Properties producerConfig = ClientUtils.producerConfig(CLUSTER.bootstrapServers(), LongSerializer.class, 36 | LongSerializer.class, new Properties() 37 | ); 38 | StreamsBuilder builder = new StreamsBuilder(); 39 | 40 | KStream, Void> edges = StreamUtils.streamFromCollection(builder, producerConfig, new KryoSerde<>(), 41 | new KryoSerde<>(), getEdges() 42 | ); 43 | KGraphStream graph = 44 | new EdgeStream<>(edges, GraphSerialized.with(new KryoSerde<>(), new KryoSerde<>(), new KryoSerde<>())); 45 | 46 | KTable, DisjointSet> sets = graph.aggregate(new ConnectedComponents<>(500L)); 47 | 48 | startStreams(builder, new KryoSerde<>(), new KryoSerde<>()); 49 | 50 | Thread.sleep(10000); 51 | 52 | List values = StreamUtils.listFromTable(streams, sets).stream() 53 | .map(kv -> kv.value.toString()) 54 | .collect(Collectors.toList()); 55 | 56 | // verify the results 57 | String expectedResultStr = "1, 2, 3, 5\n" + "6, 7\n" + "8, 9\n"; 58 | String[] result = parser(values); 59 | String[] expected = expectedResultStr.split("\n"); 60 | 61 | assertEquals("Different number of lines in expected and obtained result.", expected.length, result.length); 62 | Assert.assertArrayEquals("Different connected components.", expected, result); 63 | 64 | streams.close(); 65 | } 66 | 67 | static List, Void>> getEdges() { 68 | List, Void>> edges = new ArrayList<>(); 69 | edges.add(new KeyValue<>(new Edge<>(1L, 2L), null)); 70 | edges.add(new KeyValue<>(new Edge<>(1L, 3L), null)); 71 | edges.add(new KeyValue<>(new Edge<>(2L, 3L), null)); 72 | edges.add(new KeyValue<>(new Edge<>(1L, 5L), null)); 73 | edges.add(new KeyValue<>(new Edge<>(6L, 7L), null)); 74 | edges.add(new KeyValue<>(new Edge<>(8L, 9L), null)); 75 | return edges; 76 | } 77 | 78 | static String[] parser(List list) { 79 | int s = list.size(); 80 | String r = list.get(s - 1); // to get the final combine result which is stored at the end of result 81 | String t; 82 | list.clear(); 83 | String[] G = r.split("="); 84 | for (String value : G) { 85 | if (value.contains("[")) { 86 | String[] k = value.split("]"); 87 | t = k[0].substring(1); 88 | list.add(t); 89 | } 90 | } 91 | String[] result = list.toArray(new String[0]); 92 | Arrays.sort(result); 93 | return result; 94 | } 95 | } 96 | 97 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/utils/TestUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package io.kgraph.utils; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import java.util.Arrays; 22 | import java.util.List; 23 | 24 | import org.apache.kafka.streams.KeyValue; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import io.kgraph.Edge; 29 | 30 | public class TestUtils { 31 | private static final Logger log = LoggerFactory.getLogger(TestUtils.class); 32 | 33 | public static void compareResultAsTuples(List result, String expected) { 34 | compareResult(result, expected, true, true); 35 | } 36 | 37 | public static void compareResultAsText(List result, String expected) { 38 | compareResult(result, expected, 39 | false, true); 40 | } 41 | 42 | public static void compareOrderedResultAsText(List result, String expected) { 43 | compareResult(result, expected, false, false); 44 | } 45 | 46 | public static void compareOrderedResultAsText(List result, String expected, boolean asTuples) { 47 | compareResult(result, expected, asTuples, false); 48 | } 49 | 50 | private static void compareResult(List result, String expected, boolean asTuples, boolean sort) { 51 | String[] expectedStrings = expected.split("\n"); 52 | String[] resultStrings = new String[result.size()]; 53 | 54 | for (int i = 0; i < resultStrings.length; i++) { 55 | T val = result.get(i); 56 | 57 | if (asTuples) { 58 | if (val instanceof KeyValue) { 59 | KeyValue t = (KeyValue) val; 60 | Object first = t.key; 61 | String firstString; 62 | if (first instanceof Edge) { 63 | Edge edge = (Edge) first; 64 | firstString = edge.source() + "," + edge.target(); 65 | } else if (first != null) { 66 | firstString = first.toString(); 67 | } else { 68 | firstString = "null"; 69 | } 70 | Object next = t.value; 71 | resultStrings[i] = firstString + ',' + (next == null ? "null" : next.toString()); 72 | } else { 73 | throw new IllegalArgumentException(val + " is no tuple"); 74 | } 75 | } else { 76 | resultStrings[i] = (val == null) ? "null" : val.toString(); 77 | } 78 | } 79 | 80 | if (sort) { 81 | Arrays.sort(expectedStrings); 82 | Arrays.sort(resultStrings); 83 | } 84 | 85 | // Include content of both arrays to provide more context in case of a test failure 86 | String msg = String.format( 87 | "Different elements in arrays: expected %d elements and received %d\n expected: %s\n received: %s", 88 | expectedStrings.length, resultStrings.length, 89 | Arrays.toString(expectedStrings), Arrays.toString(resultStrings)); 90 | 91 | assertEquals(msg, expectedStrings.length, resultStrings.length); 92 | 93 | for (int i = 0; i < expectedStrings.length; i++) { 94 | assertEquals(msg, expectedStrings[i], resultStrings[i]); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/KryoUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import com.esotericsoftware.kryo.Kryo; 22 | import com.esotericsoftware.kryo.io.Input; 23 | import com.esotericsoftware.kryo.io.Output; 24 | import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy; 25 | import com.esotericsoftware.kryo.util.Pool; 26 | import de.javakaffee.kryoserializers.CollectionsEmptyListSerializer; 27 | import de.javakaffee.kryoserializers.CollectionsEmptyMapSerializer; 28 | import de.javakaffee.kryoserializers.CollectionsEmptySetSerializer; 29 | import de.javakaffee.kryoserializers.CollectionsSingletonListSerializer; 30 | import de.javakaffee.kryoserializers.CollectionsSingletonMapSerializer; 31 | import de.javakaffee.kryoserializers.CollectionsSingletonSetSerializer; 32 | import de.javakaffee.kryoserializers.SynchronizedCollectionsSerializer; 33 | import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer; 34 | import org.objenesis.strategy.StdInstantiatorStrategy; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | import java.io.ByteArrayOutputStream; 39 | import java.util.Collections; 40 | import java.util.List; 41 | import java.util.Map; 42 | import java.util.Set; 43 | 44 | public class KryoUtils { 45 | private static final Logger log = LoggerFactory.getLogger(KryoUtils.class); 46 | 47 | private static final List SINGLETON_LIST = Collections.singletonList(""); 48 | private static final Set SINGLETON_SET = Collections.singleton(""); 49 | private static final Map SINGLETON_MAP = Collections.singletonMap("", ""); 50 | 51 | // Pool constructor arguments: thread safe, soft references 52 | private static final Pool kryoPool = new Pool<>(true, true) { 53 | protected Kryo create() { 54 | Kryo kryo = new Kryo(); 55 | kryo.register(Collections.EMPTY_LIST.getClass(), new CollectionsEmptyListSerializer()); 56 | kryo.register(Collections.EMPTY_MAP.getClass(), new CollectionsEmptyMapSerializer()); 57 | kryo.register(Collections.EMPTY_SET.getClass(), new CollectionsEmptySetSerializer()); 58 | kryo.register(SINGLETON_LIST.getClass(), new CollectionsSingletonListSerializer()); 59 | kryo.register(SINGLETON_SET.getClass(), new CollectionsSingletonSetSerializer()); 60 | kryo.register(SINGLETON_MAP.getClass(), new CollectionsSingletonMapSerializer()); 61 | kryo.setRegistrationRequired(false); 62 | 63 | UnmodifiableCollectionsSerializer.registerSerializers(kryo); 64 | SynchronizedCollectionsSerializer.registerSerializers(kryo); 65 | ((DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy()).setFallbackInstantiatorStrategy(new 66 | StdInstantiatorStrategy()); 67 | return kryo; 68 | } 69 | }; 70 | 71 | public static byte[] serialize(final Object obj) { 72 | Kryo kryo = kryoPool.obtain(); 73 | try { 74 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 75 | Output output = new Output(stream); 76 | kryo.writeClassAndObject(output, obj); 77 | output.close(); 78 | return stream.toByteArray(); 79 | } finally { 80 | kryoPool.free(kryo); 81 | } 82 | } 83 | 84 | @SuppressWarnings("unchecked") 85 | public static V deserialize(final byte[] objectData) { 86 | Kryo kryo = kryoPool.obtain(); 87 | try { 88 | Input input = new Input(objectData); 89 | return (V) kryo.readClassAndObject(input); 90 | } finally { 91 | kryoPool.free(kryo); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/streaming/SummaryAggregation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming; 20 | 21 | import org.apache.kafka.streams.kstream.KStream; 22 | import org.apache.kafka.streams.kstream.KTable; 23 | import org.apache.kafka.streams.kstream.Reducer; 24 | import org.apache.kafka.streams.kstream.ValueMapper; 25 | import org.apache.kafka.streams.kstream.Windowed; 26 | 27 | import io.kgraph.Edge; 28 | 29 | /** 30 | * @param key type 31 | * @param edge value type 32 | * @param intermediate state type 33 | * @param fold result type 34 | */ 35 | public abstract class SummaryAggregation { 36 | 37 | /** 38 | * A function applied to each edge in an edge stream that aggregates a user-defined graph property state. In case 39 | * we slice the edge stream into windows a fold will output its aggregation state value per window, otherwise, this 40 | * operates edge-wise 41 | */ 42 | private final EdgeFoldFunction updateFun; 43 | 44 | /** 45 | * An optional combine function for updating graph property state 46 | */ 47 | private final Reducer combineFun; 48 | 49 | /** 50 | * An optional map function that converts state to output 51 | */ 52 | private final ValueMapper transform; 53 | 54 | private final S initialValue; 55 | 56 | /** 57 | * This flag indicates whether a merger state is cleaned up after an operation 58 | */ 59 | private final boolean transientState; 60 | 61 | protected SummaryAggregation(EdgeFoldFunction updateFun, Reducer combineFun, ValueMapper transform, S initialValue, boolean transientState) { 62 | this.updateFun = updateFun; 63 | this.combineFun = combineFun; 64 | this.transform = transform; 65 | this.initialValue = initialValue; 66 | this.transientState = transientState; 67 | } 68 | 69 | public abstract KTable, T> run(KStream, EV> edgeStream); 70 | 71 | public Reducer combineFun() { 72 | return combineFun; 73 | } 74 | 75 | public EdgeFoldFunction updateFun() { 76 | return updateFun; 77 | } 78 | 79 | public ValueMapper transform() { 80 | return transform; 81 | } 82 | 83 | public boolean isTransientState() { 84 | return transientState; 85 | } 86 | 87 | public S initialValue() { 88 | return initialValue; 89 | } 90 | 91 | protected ValueMapper aggregator(final KStream, EV> edgeStream) { 92 | return new Merger<>(initialValue(), combineFun(), isTransientState()); 93 | } 94 | 95 | /** 96 | * In this prototype the Merger is non-blocking and merges partitions incrementally 97 | * 98 | * @param 99 | */ 100 | private static final class Merger implements ValueMapper { 101 | 102 | private final S initialVal; 103 | private final Reducer combiner; 104 | private S summary; 105 | private final boolean transientState; 106 | 107 | private Merger(S initialVal, Reducer combiner, boolean transientState) { 108 | this.initialVal = initialVal; 109 | this.combiner = combiner; 110 | this.summary = initialVal; 111 | this.transientState = transientState; 112 | } 113 | 114 | @Override 115 | public S apply(S s) { 116 | if (combiner != null) { 117 | summary = combiner.apply(s, summary); 118 | if (transientState) { 119 | summary = initialVal; 120 | } 121 | return summary; 122 | } else { 123 | return s; 124 | } 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/PageRank.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import java.util.Map; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import io.kgraph.EdgeWithValue; 27 | import io.kgraph.VertexWithValue; 28 | import io.kgraph.pregel.ComputeFunction; 29 | import io.kgraph.pregel.aggregators.DoubleSumAggregator; 30 | import io.vavr.Tuple2; 31 | 32 | public class PageRank implements ComputeFunction, Double, Double> { 33 | private static final Logger log = LoggerFactory.getLogger(PageRank.class); 34 | 35 | public static final String TOLERANCE = "tolerance"; 36 | public static final String RESET_PROBABILITY = "resetProbability"; 37 | public static final String SRC_VERTEX_ID = "srcVertexId"; 38 | public static final String RUNNING_SUM = "running.sum"; 39 | 40 | private double tolerance; 41 | private double resetProbability; 42 | private K srcVertexId; 43 | 44 | @Override 45 | @SuppressWarnings("unchecked") 46 | public void init(Map configs, InitCallback cb) { 47 | tolerance = (Double) configs.get(TOLERANCE); 48 | resetProbability = (Double) configs.get(RESET_PROBABILITY); 49 | srcVertexId = (K) configs.get(SRC_VERTEX_ID); 50 | 51 | cb.registerAggregator(RUNNING_SUM, DoubleSumAggregator.class, true); 52 | } 53 | 54 | @Override 55 | public void masterCompute(int superstep, MasterCallback cb) { 56 | double sum = cb.getAggregatedValue(RUNNING_SUM); 57 | log.info("Running sum: " + sum); 58 | } 59 | 60 | @Override 61 | public void compute( 62 | int superstep, 63 | VertexWithValue> vertex, 64 | Iterable messages, 65 | Iterable> edges, 66 | Callback, Double, Double> cb) { 67 | 68 | if (superstep == 0) { 69 | int count = 0; 70 | for (EdgeWithValue edge : edges) { 71 | count++; 72 | } 73 | for (EdgeWithValue edge : edges) { 74 | cb.setNewEdgeValue(edge.target(), 1.0 / count); 75 | } 76 | for (Double message : messages) { 77 | // Resend initial message to self 78 | cb.sendMessageTo(vertex.id(), message); 79 | } 80 | } else { 81 | double oldPageRank = vertex.value()._1; 82 | double oldDelta = vertex.value()._2; 83 | 84 | double messageSum = 0.0; 85 | for (Double message : messages) { 86 | messageSum += message; 87 | } 88 | 89 | boolean isPersonalized = srcVertexId != null; 90 | double newPageRank = isPersonalized && oldDelta == Double.NEGATIVE_INFINITY 91 | ? 1.0 : oldPageRank + (1.0 - resetProbability) * messageSum; 92 | double newDelta = newPageRank - oldPageRank; 93 | 94 | log.debug("step {} vertex {} sum {}", superstep, vertex.id(), messageSum); 95 | log.debug("old ({},{})", oldPageRank, oldDelta); 96 | log.debug("new ({},{})", newPageRank, newDelta); 97 | log.debug("msgs {}", messages); 98 | 99 | cb.setNewVertexValue(new Tuple2<>(newPageRank, newDelta)); 100 | 101 | cb.aggregate(RUNNING_SUM, newPageRank); 102 | 103 | for (EdgeWithValue edge : edges) { 104 | if (newDelta > tolerance) { 105 | log.debug("sending to target {} edge {} msg {}", edge.target(), edge.value(), newDelta * edge.value()); 106 | cb.sendMessageTo(edge.target(), newDelta * edge.value()); 107 | } 108 | } 109 | 110 | cb.voteToHalt(); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/utils/GraphGenerators.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.utils; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | import java.util.Properties; 24 | import java.util.function.BiFunction; 25 | 26 | import org.apache.kafka.common.serialization.Serdes; 27 | import org.apache.kafka.streams.KeyValue; 28 | import org.apache.kafka.streams.StreamsBuilder; 29 | import org.apache.kafka.streams.kstream.Grouped; 30 | import org.apache.kafka.streams.kstream.KTable; 31 | import org.apache.kafka.streams.kstream.Materialized; 32 | 33 | import io.kgraph.Edge; 34 | import io.kgraph.GraphSerialized; 35 | import io.kgraph.KGraph; 36 | import io.vavr.Tuple2; 37 | 38 | public class GraphGenerators { 39 | 40 | public static KGraph completeGraph( 41 | StreamsBuilder builder, Properties producerConfig, int numVertices) { 42 | List, Long>> edgeList = new ArrayList<>(); 43 | for (long i = 0; i < numVertices; i++) { 44 | for (long j = 0; j < numVertices; j++) { 45 | if (i != j) edgeList.add(new KeyValue<>(new Edge<>(i, j), 1L)); 46 | } 47 | } 48 | KTable, Long> edges = StreamUtils.tableFromCollection( 49 | builder, producerConfig, new KryoSerde<>(), Serdes.Long(), edgeList); 50 | 51 | return KGraph.fromEdges(edges, v -> 1L, 52 | GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Long())); 53 | } 54 | 55 | public static KGraph, Long> gridGraph( 56 | StreamsBuilder builder, Properties producerConfig, int numRows, int numCols) { 57 | BiFunction posToIdx = (row, col) -> row * numCols + col; 58 | List>> vertexList = new ArrayList<>(); 59 | for (long row = 0; row < numRows; row++) { 60 | for (long col = 0; col < numCols; col++) { 61 | vertexList.add(new KeyValue<>(posToIdx.apply(row, col), new Tuple2<>(row, col))); 62 | } 63 | } 64 | KTable> vertices = StreamUtils.tableFromCollection( 65 | builder, producerConfig, Serdes.Long(), new KryoSerde<>(), vertexList); 66 | 67 | KTable, Long> edges = vertices 68 | .toStream() 69 | .flatMap((v, tuple) -> { 70 | List, Long>> result = new ArrayList<>(); 71 | long row = tuple._1; 72 | long col = tuple._2; 73 | if (row + 1 < numRows) { 74 | result.add(new KeyValue<>(new Edge<>(posToIdx.apply(row, col), posToIdx.apply(row + 1, col)), 1L)); 75 | } 76 | if (col + 1 < numCols) { 77 | result.add(new KeyValue<>(new Edge<>(posToIdx.apply(row, col), posToIdx.apply(row, col + 1)), 1L)); 78 | } 79 | return result; 80 | }) 81 | .groupByKey(Grouped.with(new KryoSerde<>(), Serdes.Long())) 82 | .reduce((v1, v2) -> v2, Materialized.with(new KryoSerde<>(), Serdes.Long())); 83 | 84 | return new KGraph<>(vertices, edges, GraphSerialized.with(Serdes.Long(), new KryoSerde<>(), Serdes.Long())); 85 | } 86 | 87 | public static KGraph starGraph( 88 | StreamsBuilder builder, Properties producerConfig, int numVertices) { 89 | List, Long>> edgeList = new ArrayList<>(); 90 | for (long i = 1; i < numVertices; i++) { 91 | edgeList.add(new KeyValue<>(new Edge<>(i, 0L), 1L)); 92 | } 93 | KTable, Long> edges = StreamUtils.tableFromCollection( 94 | builder, producerConfig, new KryoSerde<>(), Serdes.Long(), edgeList); 95 | 96 | return KGraph.fromEdges(edges, v -> 1L, 97 | GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Long())); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/streaming/KGraphWindowedStream.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.streaming; 20 | 21 | import org.apache.kafka.streams.kstream.Aggregator; 22 | import org.apache.kafka.streams.kstream.KTable; 23 | import org.apache.kafka.streams.kstream.Reducer; 24 | import org.apache.kafka.streams.kstream.TimeWindowedKStream; 25 | import org.apache.kafka.streams.kstream.Windowed; 26 | import org.apache.kafka.streams.kstream.Windows; 27 | 28 | import io.kgraph.EdgeWithValue; 29 | 30 | /** 31 | * A stream of discrete graphs, each maintaining 32 | * the graph state of the edges contained in the respective window. 33 | * It is created by calling {@link KGraphStream#slice(Windows)}. 34 | * The graph slice is keyed by the source or target vertex of the edge stream, 35 | * so that all edges of a vertex are in the same tumbling window. 36 | * 37 | * @param the vertex ID type 38 | * @param the edge value type 39 | */ 40 | public class KGraphWindowedStream { 41 | 42 | private final TimeWindowedKStream> windowedStream; 43 | 44 | KGraphWindowedStream(TimeWindowedKStream> window) { 45 | this.windowedStream = window; 46 | } 47 | 48 | /** 49 | * Performs a neighborhood fold on the graph window stream. 50 | * 51 | * @param the type of the initial value 52 | * @param initialValue the initial value 53 | * @param foldFunction the fold function 54 | * @return the result stream after applying the user-defined fold operation on the window 55 | */ 56 | public KTable, T> foldNeighbors(T initialValue, final EdgeFoldFunction foldFunction) { 57 | return windowedStream.aggregate(() -> initialValue, new ApplyEdgesFoldFunction(foldFunction)); 58 | } 59 | 60 | public static final class ApplyEdgesFoldFunction 61 | implements Aggregator, T> { 62 | 63 | private final EdgeFoldFunction foldFunction; 64 | 65 | public ApplyEdgesFoldFunction(EdgeFoldFunction foldFunction) { 66 | this.foldFunction = foldFunction; 67 | } 68 | 69 | @Override 70 | public T apply(K vertex, EdgeWithValue edge, T accumulator) { 71 | return foldFunction.foldEdges(accumulator, edge.source(), edge.target(), edge.value()); 72 | } 73 | } 74 | 75 | /** 76 | * Performs an aggregation on the neighboring edges of each vertex on the graph window stream. 77 | *

78 | * For each vertex, the transformation consecutively calls a 79 | * {@link EdgeReduceFunction} function until only a single value for each edge remains. 80 | * The {@link EdgeReduceFunction} function combines two edge values into one new value of the same type. 81 | * 82 | * @param reduceFunction the aggregation function 83 | * @return a result stream of Tuple2, containing one tuple per vertex. 84 | * The first field is the vertex ID and the second field is the final value, 85 | * after applying the user-defined aggregation operation on the neighborhood. 86 | */ 87 | public KTable, EV> reduceOnEdges(final EdgeReduceFunction reduceFunction) { 88 | return windowedStream.reduce(new ApplyEdgesReduceFunction(reduceFunction)) 89 | .mapValues(EdgeWithValue::value); 90 | } 91 | 92 | public static final class ApplyEdgesReduceFunction implements Reducer> { 93 | 94 | private final EdgeReduceFunction reduceFunction; 95 | 96 | public ApplyEdgesReduceFunction(EdgeReduceFunction reduceFunction) { 97 | this.reduceFunction = reduceFunction; 98 | } 99 | 100 | @Override 101 | public EdgeWithValue apply(EdgeWithValue firstEdge, EdgeWithValue secondEdge) { 102 | EV reducedValue = reduceFunction.reduceEdges(firstEdge.value(), secondEdge.value()); 103 | return new EdgeWithValue(firstEdge.source(), firstEdge.target(), reducedValue); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/main/java/io/kgraph/library/GraphAlgorithmType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | package io.kgraph.library; 20 | 21 | import java.util.HashMap; 22 | 23 | import org.apache.kafka.common.serialization.Serdes; 24 | import org.apache.kafka.streams.kstream.ValueMapper; 25 | import org.jblas.FloatMatrix; 26 | 27 | import io.kgraph.GraphSerialized; 28 | import io.kgraph.library.cf.CfLongIdSerde; 29 | import io.kgraph.library.cf.Svdpp; 30 | import io.kgraph.pregel.ComputeFunction; 31 | import io.kgraph.utils.KryoSerde; 32 | 33 | public enum GraphAlgorithmType { 34 | bfs, 35 | lcc, 36 | lp, 37 | mssp, 38 | pagerank, 39 | sssp, 40 | svdpp, 41 | wcc; 42 | 43 | public static ComputeFunction computeFunction(GraphAlgorithmType type) { 44 | switch (type) { 45 | case bfs: 46 | return new BreadthFirstSearch<>(); 47 | case lcc: 48 | return new LocalClusteringCoefficient(); 49 | case lp: 50 | return new LabelPropagation<>(); 51 | case mssp: 52 | return new MultipleSourceShortestPaths(); 53 | case pagerank: 54 | return new PageRank<>(); 55 | case sssp: 56 | return new SingleSourceShortestPaths(); 57 | case svdpp: 58 | return new Svdpp(); 59 | case wcc: 60 | return new ConnectedComponents<>(); 61 | default: 62 | throw new IllegalArgumentException("Unsupported algorithm type"); 63 | } 64 | } 65 | 66 | public static GraphSerialized graphSerialized(GraphAlgorithmType type, boolean useDouble) { 67 | switch (type) { 68 | case bfs: 69 | return useDouble 70 | ? GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Double()) 71 | : GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Long()); 72 | case lcc: 73 | return GraphSerialized.with(Serdes.Long(), Serdes.Double(), Serdes.Double()); 74 | case lp: 75 | return useDouble 76 | ? GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Double()) 77 | : GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Long()); 78 | case mssp: 79 | return GraphSerialized.with(Serdes.Long(), new KryoSerde<>(), Serdes.Double()); 80 | case pagerank: 81 | return GraphSerialized.with(Serdes.Long(), new KryoSerde<>(), Serdes.Double()); 82 | case sssp: 83 | return GraphSerialized.with(Serdes.Long(), Serdes.Double(), Serdes.Double()); 84 | case svdpp: 85 | return GraphSerialized.with(new CfLongIdSerde(), new KryoSerde<>(), Serdes.Float()); 86 | case wcc: 87 | return useDouble 88 | ? GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Double()) 89 | : GraphSerialized.with(Serdes.Long(), Serdes.Long(), Serdes.Long()); 90 | default: 91 | throw new IllegalArgumentException("Unsupported algorithm type"); 92 | } 93 | } 94 | 95 | public static ValueMapper initialVertexValueMapper(GraphAlgorithmType type) { 96 | switch (type) { 97 | case bfs: 98 | return id -> BreadthFirstSearch.UNVISITED; 99 | case lcc: 100 | return id -> 1.0; 101 | case lp: 102 | return id -> id; 103 | case mssp: 104 | return id -> new HashMap<>(); 105 | case pagerank: 106 | return id -> Double.POSITIVE_INFINITY; 107 | case sssp: 108 | return id -> Double.POSITIVE_INFINITY; 109 | case svdpp: 110 | return id -> new Svdpp.SvdppValue(0f, new FloatMatrix(), new FloatMatrix()); 111 | case wcc: 112 | return id -> id; 113 | default: 114 | throw new IllegalArgumentException("Unsupported algorithm type"); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /kafka-graphs-core/src/test/java/io/kgraph/streaming/library/BipartitenessCheckTest.java: -------------------------------------------------------------------------------- 1 | package io.kgraph.streaming.library; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import com.google.common.collect.Lists; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Properties; 10 | import java.util.stream.Collectors; 11 | 12 | import org.apache.kafka.common.serialization.LongSerializer; 13 | import org.apache.kafka.streams.KeyValue; 14 | import org.apache.kafka.streams.StreamsBuilder; 15 | import org.apache.kafka.streams.kstream.KStream; 16 | import org.apache.kafka.streams.kstream.KTable; 17 | import org.apache.kafka.streams.kstream.Windowed; 18 | import org.junit.Test; 19 | 20 | import io.kgraph.AbstractIntegrationTest; 21 | import io.kgraph.Edge; 22 | import io.kgraph.GraphSerialized; 23 | import io.kgraph.streaming.KGraphStream; 24 | import io.kgraph.streaming.EdgeStream; 25 | import io.kgraph.streaming.summaries.Candidates; 26 | import io.kgraph.utils.ClientUtils; 27 | import io.kgraph.utils.KryoSerde; 28 | import io.kgraph.utils.StreamUtils; 29 | 30 | public class BipartitenessCheckTest extends AbstractIntegrationTest { 31 | 32 | @Test 33 | public void testBipartite() throws Exception { 34 | 35 | Properties producerConfig = ClientUtils.producerConfig(CLUSTER.bootstrapServers(), LongSerializer.class, 36 | LongSerializer.class, new Properties() 37 | ); 38 | StreamsBuilder builder = new StreamsBuilder(); 39 | 40 | KStream, Void> edges = StreamUtils.streamFromCollection(builder, producerConfig, new KryoSerde<>(), 41 | new KryoSerde<>(), getBipartiteEdges() 42 | ); 43 | KGraphStream graph = 44 | new EdgeStream<>(edges, GraphSerialized.with(new KryoSerde<>(), new KryoSerde<>(), new KryoSerde<>())); 45 | 46 | KTable, Candidates> candidates = graph.aggregate(new BipartitenessCheck<>(500L)); 47 | 48 | startStreams(builder, new KryoSerde<>(), new KryoSerde<>()); 49 | 50 | Thread.sleep(10000); 51 | 52 | List result = StreamUtils.listFromTable(streams, candidates).stream() 53 | .map(kv -> kv.value.toString()) 54 | .collect(Collectors.toList()); 55 | 56 | // verify the results 57 | assertEquals( 58 | Lists.newArrayList( 59 | "(true,{1={1=(1,true), 2=(2,false), 3=(3,false), 4=(4,false), 5=(5,true), 7=(7,true), 9=(9,true)}})"), 60 | result 61 | ); 62 | 63 | streams.close(); 64 | } 65 | 66 | @Test 67 | public void testNonBipartite() throws Exception { 68 | 69 | Properties producerConfig = ClientUtils.producerConfig(CLUSTER.bootstrapServers(), LongSerializer.class, 70 | LongSerializer.class, new Properties() 71 | ); 72 | StreamsBuilder builder = new StreamsBuilder(); 73 | 74 | KStream, Void> edges = StreamUtils.streamFromCollection(builder, producerConfig, new KryoSerde<>(), 75 | new KryoSerde<>(), getNonBipartiteEdges() 76 | ); 77 | KGraphStream graph = 78 | new EdgeStream<>(edges, GraphSerialized.with(new KryoSerde<>(), new KryoSerde<>(), new KryoSerde<>())); 79 | 80 | KTable, Candidates> candidates = graph.aggregate(new BipartitenessCheck<>(500L)); 81 | 82 | startStreams(builder, new KryoSerde<>(), new KryoSerde<>()); 83 | 84 | Thread.sleep(10000); 85 | 86 | List result = StreamUtils.listFromTable(streams, candidates).stream() 87 | .map(kv -> kv.value.toString()) 88 | .collect(Collectors.toList()); 89 | 90 | // verify the results 91 | assertEquals( 92 | Lists.newArrayList( 93 | "(false,{})"), 94 | result 95 | ); 96 | 97 | streams.close(); 98 | } 99 | 100 | static List, Void>> getBipartiteEdges() { 101 | List, Void>> edges = new ArrayList<>(); 102 | edges.add(new KeyValue<>(new Edge<>(1L, 2L), null)); 103 | edges.add(new KeyValue<>(new Edge<>(1L, 3L), null)); 104 | edges.add(new KeyValue<>(new Edge<>(1L, 4L), null)); 105 | edges.add(new KeyValue<>(new Edge<>(4L, 5L), null)); 106 | edges.add(new KeyValue<>(new Edge<>(4L, 7L), null)); 107 | edges.add(new KeyValue<>(new Edge<>(4L, 9L), null)); 108 | return edges; 109 | } 110 | 111 | static List, Void>> getNonBipartiteEdges() { 112 | List, Void>> edges = new ArrayList<>(); 113 | edges.add(new KeyValue<>(new Edge<>(1L, 2L), null)); 114 | edges.add(new KeyValue<>(new Edge<>(2L, 3L), null)); 115 | edges.add(new KeyValue<>(new Edge<>(3L, 1L), null)); 116 | edges.add(new KeyValue<>(new Edge<>(4L, 5L), null)); 117 | edges.add(new KeyValue<>(new Edge<>(5L, 7L), null)); 118 | edges.add(new KeyValue<>(new Edge<>(4L, 1L), null)); 119 | return edges; 120 | } 121 | } --------------------------------------------------------------------------------