Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hama.graph; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.MapWritable; import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.WritableComparable; import org.apache.hama.HamaConfiguration; import org.apache.hama.bsp.BSPPeer; import org.apache.hama.bsp.Counters.Counter; import org.apache.hama.bsp.Partitioner; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Vertex is a abstract definition of Google Pregel Vertex. For implementing a * graph application, one must implement a sub-class of Vertex and define, the * message passing and message processing for each vertex. * * Every vertex should be assigned an ID. This ID object should obey the * equals-hashcode contract and would be used for partitioning. * * The edges for a vertex could be accessed and modified using the * {@link Vertex#getEdges()} call. The self value of the vertex could be changed * by {@link Vertex#setValue(Writable)}. * * @param <V> Vertex ID object type * @param <E> Edge cost object type * @param <M> Vertex value object type */ @SuppressWarnings("rawtypes") public abstract class Vertex<V extends WritableComparable, E extends Writable, M extends Writable> implements VertexInterface<V, E, M> { private transient GraphJobRunner<V, E, M> runner; private V vertexID; private M oldValue; private M value; private List<Edge<V, E>> edges; private static final Log LOG = LogFactory.getLog(Vertex.class); private boolean votedToHalt = false; public HamaConfiguration getConf() { return runner.getPeer().getConfiguration(); } @Override public V getVertexID() { return this.vertexID; } @Override public void setup(HamaConfiguration conf) { } @Override public void sendMessage(Edge<V, E> e, M msg) throws IOException { runner.getPeer().send(getDestinationPeerName(e), new GraphJobMessage(e.getDestinationVertexID(), msg, vertexID)); } /** * @return the destination peer name of the destination of the given directed * edge. */ public String getDestinationPeerName(Edge<V, E> edge) { return getDestinationPeerName(edge.getDestinationVertexID()); } /** * @return the destination peer name of the given vertex id, determined by the * partitioner. */ public String getDestinationPeerName(V vertexId) { return runner.getPeer() .getPeerName(getPartitioner().getPartition(vertexId, value, runner.getPeer().getNumPeers())); } @Override public void sendMessageToNeighbors(M msg) throws IOException { final List<Edge<V, E>> outEdges = this.getEdges(); for (Edge<V, E> e : outEdges) { sendMessage(e, msg); } } @Override public void sendMessage(V destinationVertexID, M msg) throws IOException { int partition = getPartitioner().getPartition(destinationVertexID, msg, runner.getPeer().getNumPeers()); String destPeer = runner.getPeer().getAllPeerNames()[partition]; runner.getPeer().send(destPeer, new GraphJobMessage(destinationVertexID, msg, vertexID)); } private void alterVertexCounter(int i) throws IOException { this.runner.setChangedVertexCnt(this.runner.getChangedVertexCnt() + i); } @Override public void addVertex(V vertexID, List<Edge<V, E>> edges, M value) throws IOException { MapWritable msg = new MapWritable(); // Create the new vertex. Vertex<V, E, M> vertex = GraphJobRunner.<V, E, M>newVertexInstance(GraphJobRunner.VERTEX_CLASS); vertex.setEdges(edges); vertex.setValue(value); vertex.setVertexID(vertexID); msg.put(GraphJobRunner.FLAG_VERTEX_INCREASE, vertex); // Find the proper partition to host the new vertex. int partition = getPartitioner().getPartition(vertexID, value, runner.getPeer().getNumPeers()); String destPeer = runner.getPeer().getAllPeerNames()[partition]; runner.getPeer().send(destPeer, new GraphJobMessage(msg)); alterVertexCounter(1); } @Override public void remove() throws IOException { MapWritable msg = new MapWritable(); msg.put(GraphJobRunner.FLAG_VERTEX_DECREASE, this.vertexID); // Get master task peer. String destPeer = GraphJobRunner.getMasterTask(this.getPeer()); runner.getPeer().send(destPeer, new GraphJobMessage(msg)); alterVertexCounter(-1); } @Override public long getSuperstepCount() { return runner.getNumberIterations(); } public void setEdges(List<Edge<V, E>> list) { this.edges = list; } public void addEdge(Edge<V, E> edge) { if (edges == null) { this.edges = new ArrayList<Edge<V, E>>(); } this.edges.add(edge); } @Override public List<Edge<V, E>> getEdges() { return (edges == null) ? new ArrayList<Edge<V, E>>() : edges; } @Override public M getValue() { return this.value; } @Override public void setValue(M value) { this.oldValue = this.value; this.value = value; //LOG.info("Setting " + vertexID + " value " + value); } public void setVertexID(V vertexID) { this.vertexID = vertexID; } public int getMaxIteration() { return runner.getMaxIteration(); } public int getNumPeers() { return runner.getPeer().getNumPeers(); } /** * Gives access to the BSP primitives and additional features by a peer. */ public BSPPeer<Writable, Writable, Writable, Writable, GraphJobMessage> getPeer() { return runner.getPeer(); } /** * @return the configured partitioner instance to message vertices. */ public Partitioner<V, M> getPartitioner() { return runner.getPartitioner(); } @Override public long getNumVertices() { return runner.getNumberVertices(); } @Override public void voteToHalt() { this.votedToHalt = true; } void setActive() { this.votedToHalt = false; } public boolean isHalted() { return votedToHalt; } void setVotedToHalt(boolean votedToHalt) { this.votedToHalt = votedToHalt; } @Override public int hashCode() { return ((vertexID == null) ? 0 : vertexID.hashCode()); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Vertex<?, ?, ?> other = (Vertex<?, ?, ?>) obj; if (vertexID == null) { if (other.vertexID != null) return false; } else if (!vertexID.equals(other.vertexID)) return false; return true; } @Override public String toString() { return "Active: " + !votedToHalt + " -> ID: " + getVertexID() + (getValue() != null ? " = " + getValue() : "") + " // " + edges; } @Override public void readFields(DataInput in) throws IOException { if (in.readBoolean()) { if (this.vertexID == null) { this.vertexID = GraphJobRunner.createVertexIDObject(); } this.vertexID.readFields(in); } if (in.readBoolean()) { if (this.value == null) { this.value = GraphJobRunner.createVertexValue(); } this.value.readFields(in); } this.edges = new ArrayList<Edge<V, E>>(); if (in.readBoolean()) { int num = in.readInt(); if (num > 0) { for (int i = 0; i < num; ++i) { V vertex = GraphJobRunner.createVertexIDObject(); vertex.readFields(in); E edgeCost = null; if (in.readBoolean()) { edgeCost = GraphJobRunner.createEdgeCostObject(); edgeCost.readFields(in); } Edge<V, E> edge = new Edge<V, E>(vertex, edgeCost); this.edges.add(edge); } } } votedToHalt = in.readBoolean(); readState(in); } @Override public void write(DataOutput out) throws IOException { if (vertexID == null) { out.writeBoolean(false); } else { out.writeBoolean(true); vertexID.write(out); } if (value == null) { out.writeBoolean(false); } else { out.writeBoolean(true); value.write(out); } if (this.edges == null) { out.writeBoolean(false); } else { out.writeBoolean(true); out.writeInt(this.edges.size()); for (Edge<V, E> edge : this.edges) { edge.getDestinationVertexID().write(out); if (edge.getValue() == null) { out.writeBoolean(false); } else { out.writeBoolean(true); edge.getValue().write(out); } } } out.writeBoolean(votedToHalt); writeState(out); } // compare across the vertex ID @SuppressWarnings("unchecked") @Override public final int compareTo(VertexInterface<V, E, M> o) { return getVertexID().compareTo(o.getVertexID()); } /** * Read the state of the vertex from the input stream. The framework would * have already constructed and loaded the vertex-id, edges and voteToHalt * state. This function is essential if there is any more properties of vertex * to be read from. */ public void readState(DataInput in) throws IOException { } /** * Writes the state of vertex to the output stream. The framework writes the * vertex and edge information to the output stream. This function could be * used to save the state variable of the vertex added in the implementation * of object. */ public void writeState(DataOutput out) throws IOException { } protected void setRunner(GraphJobRunner<V, E, M> runner) { this.runner = runner; } protected GraphJobRunner<V, E, M> getRunner() { return runner; } @Override public void aggregate(int index, M value) throws IOException { this.runner.getAggregationRunner().aggregateVertex(index, oldValue, value); } /** * Get the last aggregated value of the defined aggregator, null if nothing * was configured or not returned a result. You have to supply an index, the * index is defined by the order you set the aggregator classes in * {@link GraphJob#setAggregatorClass(Class...)}. Index is starting at zero, * so if you have a single aggregator you can retrieve it via * {@link GraphJobRunner#getLastAggregatedValue}(0). */ @SuppressWarnings("unchecked") @Override public M getAggregatedValue(int index) { return (M) runner.getLastAggregatedValue(index); } /** * Get the number of aggregated vertices in the last superstep. Or null if no * aggregator is available.You have to supply an index, the index is defined * by the order you set the aggregator classes in * {@link GraphJob#setAggregatorClass(Class...)}. Index is starting at zero, * so if you have a single aggregator you can retrieve it via * {@link #getNumLastAggregatedVertices}(0). */ public IntWritable getNumLastAggregatedVertices(int index) { return runner.getNumLastAggregatedVertices(index); } @Override public Counter getCounter(Enum<?> name) { return runner.getPeer().getCounter(name); } @Override public Counter getCounter(String group, String name) { return runner.getPeer().getCounter(group, name); } }