package com.thinkaurelius.faunus;
import com.tinkerpop.blueprints.Direction;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Vertex;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.SequenceFile;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static com.tinkerpop.blueprints.Direction.*;
/**
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public class FaunusVertexTest extends BaseTest {
public void testRawComparator() throws IOException {
FaunusVertex vertex1 = new FaunusVertex(10);
FaunusVertex vertex2 = new FaunusVertex(11);
ByteArrayOutputStream bytes1 = new ByteArrayOutputStream();
vertex1.write(new DataOutputStream(bytes1));
ByteArrayOutputStream bytes2 = new ByteArrayOutputStream();
vertex2.write(new DataOutputStream(bytes2));
assertEquals(-1, new FaunusVertex.Comparator().compare(bytes1.toByteArray(), 0, bytes1.size(), bytes2.toByteArray(), 0, bytes2.size()));
assertEquals(1, new FaunusVertex.Comparator().compare(bytes2.toByteArray(), 0, bytes2.size(), bytes1.toByteArray(), 0, bytes1.size()));
assertEquals(0, new FaunusVertex.Comparator().compare(bytes1.toByteArray(), 0, bytes1.size(), bytes1.toByteArray(), 0, bytes1.size()));
System.out.println("Vertex with 0 properties has a byte size of: " + bytes1.toByteArray().length);
}
public void testSimpleSerialization() throws IOException {
FaunusVertex vertex1 = new FaunusVertex(10l);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(bytes);
vertex1.write(out);
// id length is 1 byte (variable long)
// pathsEnabled boolean 1 byte (boolean)
// paths size 1 byte (variable int)
// properties size 1 byte (variable int)
// out edge types size 1 byte (variable int)
// in edge types size 1 byte (variable int)
assertEquals(bytes.toByteArray().length, 6);
FaunusVertex vertex2 = new FaunusVertex(new DataInputStream(new ByteArrayInputStream(bytes.toByteArray())));
System.out.println("Vertex with 0 properties has a byte size of: " + bytes.toByteArray().length);
assertEquals(vertex1, vertex2);
assertEquals(vertex1.compareTo(vertex2), 0);
assertEquals(vertex2.compareTo(vertex1), 0);
assertEquals(vertex2.getId(), 10l);
assertFalse(vertex1.hasPaths());
assertFalse(vertex2.hasPaths());
assertEquals(vertex1.pathCount(), 0);
assertEquals(vertex2.pathCount(), 0);
assertFalse(vertex1.pathEnabled);
assertFalse(vertex2.pathEnabled);
assertFalse(vertex2.getEdges(Direction.OUT).iterator().hasNext());
assertFalse(vertex2.getEdges(Direction.IN).iterator().hasNext());
assertFalse(vertex2.getEdges(Direction.BOTH).iterator().hasNext());
assertEquals(vertex2.getPropertyKeys().size(), 0);
}
public void testVertexSerialization() throws IOException {
FaunusVertex vertex1 = new FaunusVertex(10);
vertex1.addEdge(OUT, new FaunusEdge(vertex1.getIdAsLong(), 2, "knows"));
vertex1.addEdge(OUT, new FaunusEdge(vertex1.getIdAsLong(), 3, "knows"));
vertex1.setProperty("name", "marko");
vertex1.setProperty("age", 32);
vertex1.setProperty("longitude", 10.01d);
vertex1.setProperty("latitude", 11.399f);
vertex1.setProperty("size", 10l);
vertex1.setProperty("boolean", true);
assertEquals(vertex1.getPropertyKeys().size(), 6);
assertEquals(vertex1.getProperty("name"), "marko");
assertEquals(vertex1.getProperty("age"), 32);
assertEquals(vertex1.getProperty("longitude"), 10.01d);
assertEquals(vertex1.getProperty("latitude"), 11.399f);
assertEquals(vertex1.getProperty("size"), 10l);
assertTrue((Boolean) vertex1.getProperty("boolean"));
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
vertex1.write(new DataOutputStream(bytes));
FaunusVertex vertex2 = new FaunusVertex(new DataInputStream(new ByteArrayInputStream(bytes.toByteArray())));
System.out.println("Vertex with 6 properties and 2 outgoing edges has a byte size of: " + bytes.toByteArray().length);
assertEquals(vertex1, vertex2);
assertEquals(vertex1.compareTo(vertex2), 0);
assertEquals(vertex2.compareTo(vertex1), 0);
assertEquals(vertex2.getId(), 10l);
assertEquals(vertex2.getPropertyKeys().size(), 6);
assertEquals(vertex2.getProperty("name"), "marko");
assertEquals(vertex2.getProperty("age"), 32);
assertEquals(vertex2.getProperty("longitude"), 10.01d);
assertEquals(vertex2.getProperty("latitude"), 11.399f);
assertEquals(vertex1.getProperty("size"), 10l);
assertTrue((Boolean) vertex2.getProperty("boolean"));
Iterator<Edge> edges = vertex2.getEdges(Direction.OUT).iterator();
assertTrue(edges.hasNext());
assertEquals(edges.next().getLabel(), "knows");
assertTrue(edges.hasNext());
assertEquals(edges.next().getLabel(), "knows");
assertFalse(edges.hasNext());
}
public void testVertexSerializationWithPaths() throws IOException {
FaunusVertex vertex1 = new FaunusVertex(10);
vertex1.enablePath(true); // TODO: look this all over
vertex1.addEdge(OUT, new FaunusEdge(vertex1.getIdAsLong(), 2, "knows"));
vertex1.addEdge(IN, new FaunusEdge(3, vertex1.getIdAsLong(), "knows"));
vertex1.setProperty("name", "marko");
vertex1.setProperty("age", 32);
vertex1.setProperty("longitude", 10.01d);
vertex1.setProperty("latitude", 11.399f);
vertex1.setProperty("size", 10l);
assertEquals(vertex1.getPropertyKeys().size(), 5);
assertEquals(vertex1.getProperty("name"), "marko");
assertEquals(vertex1.getProperty("age"), 32);
assertEquals(vertex1.getProperty("longitude"), 10.01d);
assertEquals(vertex1.getProperty("latitude"), 11.399f);
assertEquals(vertex1.getProperty("size"), 10l);
vertex1.addPath((List) Arrays.asList(new FaunusVertex.MicroVertex(10l), new FaunusVertex.MicroVertex(1l)), false);
vertex1.addPath((List) Arrays.asList(new FaunusVertex.MicroVertex(10l), new FaunusVertex.MicroVertex(2l)), false);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
vertex1.write(new DataOutputStream(bytes));
FaunusVertex vertex2 = new FaunusVertex(new DataInputStream(new ByteArrayInputStream(bytes.toByteArray())));
System.out.println("Vertex with 4 properties and 2 paths has a byte size of: " + bytes.toByteArray().length);
assertEquals(vertex1, vertex2);
assertEquals(vertex1.compareTo(vertex2), 0);
assertEquals(vertex2.compareTo(vertex1), 0);
assertEquals(vertex2.getId(), 10l);
assertEquals(vertex2.getPropertyKeys().size(), 5);
assertEquals(vertex2.getProperty("name"), "marko");
assertEquals(vertex2.getProperty("age"), 32);
assertEquals(vertex2.getProperty("longitude"), 10.01d);
assertEquals(vertex2.getProperty("latitude"), 11.399f);
assertEquals(vertex1.getProperty("size"), 10l);
assertEquals(vertex2.pathCount(), 2);
assertTrue(vertex2.hasPaths());
for (List<FaunusElement.MicroElement> path : vertex2.getPaths()) {
assertEquals(path.get(0).getId(), 10l);
assertTrue(path.get(1).getId() == 1l || path.get(1).getId() == 2l);
assertEquals(path.size(), 2);
}
Iterator<Edge> edges = vertex2.getEdges(Direction.OUT).iterator();
assertTrue(edges.hasNext());
Edge edge = edges.next();
assertEquals(edge.getLabel(), "knows");
assertEquals(edge.getVertex(Direction.IN).getId(), 2l);
assertEquals(edge.getVertex(Direction.OUT).getId(), 10l);
assertFalse(edges.hasNext());
edges = vertex2.getEdges(Direction.IN).iterator();
assertTrue(edges.hasNext());
edge = edges.next();
assertEquals(edge.getLabel(), "knows");
assertEquals(edge.getVertex(Direction.IN).getId(), 10l);
assertEquals(edge.getVertex(Direction.OUT).getId(), 3l);
assertEquals(edge.getLabel(), "knows");
assertFalse(edges.hasNext());
}
public void testVertexSerializationNoProperties() throws IOException {
FaunusVertex vertex1 = new FaunusVertex(1l);
vertex1.addEdge(OUT, new FaunusEdge(vertex1.getIdAsLong(), vertex1.getIdAsLong(), "knows"));
assertNull(vertex1.getProperty("name"));
assertNull(vertex1.removeProperty("name"));
assertEquals(vertex1.getPropertyKeys().size(), 0);
assertEquals(vertex1.getProperties().size(), 0);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
vertex1.write(new DataOutputStream(bytes));
FaunusVertex vertex2 = new FaunusVertex(new DataInputStream(new ByteArrayInputStream(bytes.toByteArray())));
System.out.println("Vertex with 0 properties and 1 outgoing edge has a byte size of: " + bytes.toByteArray().length);
assertEquals(vertex1, vertex2);
assertEquals(vertex1.getId(), 1l);
assertNull(vertex1.getProperty("name"));
assertNull(vertex1.removeProperty("name"));
assertEquals(vertex1.getPropertyKeys().size(), 0);
assertEquals(vertex1.getProperties().size(), 0);
assertEquals(asList(vertex1.getEdges(OUT)).size(), 1);
assertEquals(asList(vertex1.getEdges(IN)).size(), 0);
assertEquals(asList(vertex1.getEdges(BOTH)).size(), 1);
assertEquals(vertex2, vertex1);
assertEquals(vertex2.getId(), 1l);
assertNull(vertex2.getProperty("age"));
assertNull(vertex2.removeProperty("age"));
assertEquals(vertex2.getPropertyKeys().size(), 0);
assertEquals(vertex2.getProperties().size(), 0);
assertEquals(asList(vertex2.getEdges(OUT)).size(), 1);
assertEquals(asList(vertex2.getEdges(IN)).size(), 0);
assertEquals(asList(vertex2.getEdges(BOTH)).size(), 1);
}
public void testRemovingEdges() {
FaunusVertex vertex = new FaunusVertex(1l);
vertex.setProperty("name", "marko");
vertex.addEdge(OUT, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "knows"));
vertex.addEdge(OUT, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "created"));
assertEquals(asList(vertex.getEdges(OUT)).size(), 2);
vertex.removeEdges(Tokens.Action.DROP, OUT, "knows");
assertEquals(asList(vertex.getEdges(OUT)).size(), 1);
assertEquals(vertex.getEdges(OUT).iterator().next().getLabel(), "created");
assertEquals(vertex.getProperty("name"), "marko");
vertex = new FaunusVertex(1l);
vertex.setProperty("name", "marko");
vertex.addEdge(OUT, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "knows"));
vertex.addEdge(OUT, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "created"));
vertex.addEdge(IN, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "knows"));
vertex.addEdge(IN, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "created"));
assertEquals(asList(vertex.getEdges(OUT)).size(), 2);
vertex.removeEdges(Tokens.Action.DROP, BOTH, "knows");
assertEquals(asList(vertex.getEdges(BOTH)).size(), 2);
assertEquals(vertex.getEdges(OUT).iterator().next().getLabel(), "created");
assertEquals(vertex.getProperty("name"), "marko");
vertex = new FaunusVertex(1l);
vertex.setProperty("name", "marko");
vertex.addEdge(OUT, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "knows"));
vertex.addEdge(OUT, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "created"));
vertex.addEdge(IN, new FaunusEdge(vertex.getIdAsLong(), vertex.getIdAsLong(), "created"));
assertEquals(asList(vertex.getEdges(OUT)).size(), 2);
vertex.removeEdges(Tokens.Action.KEEP, BOTH, "knows");
assertEquals(asList(vertex.getEdges(OUT)).size(), 1);
assertEquals(vertex.getEdges(OUT).iterator().next().getLabel(), "knows");
assertEquals(vertex.getProperty("name"), "marko");
}
public void testGetVerticesAndQuery() throws Exception {
Map<Long, FaunusVertex> graph = generateGraph(ExampleGraph.TINKERGRAPH, new Configuration());
for (FaunusVertex vertex : graph.values()) {
if (vertex.getId().equals(1l)) {
assertFalse(vertex.getVertices(IN).iterator().hasNext());
assertTrue(vertex.getVertices(OUT).iterator().hasNext());
assertTrue(vertex.getVertices(BOTH).iterator().hasNext());
assertEquals(asList(vertex.getVertices(OUT)).size(), 3);
int id2 = 0;
int id3 = 0;
int id4 = 0;
for (Vertex temp : vertex.getVertices(OUT)) {
long id = (Long) temp.getId();
if (id == 2l)
id2++;
else if (id == 3l)
id3++;
else if (id == 4l)
id4++;
else
assertTrue(false);
}
assertEquals(asList(vertex.getVertices(OUT, "created")).size(), 1);
assertEquals(asList(vertex.getVertices(OUT, "knows")).size(), 2);
assertEquals(vertex.getVertices(OUT, "created").iterator().next().getId(), 3l);
assertEquals(id2, 1);
assertEquals(id3, 1);
assertEquals(id4, 1);
assertEquals(asList(vertex.query().has("weight", 0.5).limit(1).vertices()).size(), 1);
assertEquals(vertex.query().has("weight", 0.5).limit(1).vertices().iterator().next().getId(), 2l);
}
}
}
public void testGetEdges() throws Exception {
Map<Long, FaunusVertex> vertices = generateGraph(ExampleGraph.TINKERGRAPH, new Configuration());
assertEquals(asList(vertices.get(1l).getEdges(Direction.OUT, "knows")).size(), 2);
assertEquals(asList(vertices.get(1l).getEdges(Direction.OUT, "created")).size(), 1);
assertEquals(asList(vertices.get(1l).getEdges(Direction.OUT)).size(), 3);
assertEquals(asList(vertices.get(1l).getEdges(Direction.OUT, "knows", "created")).size(), 3);
assertEquals(asList(vertices.get(1l).getEdges(Direction.IN)).size(), 0);
assertEquals(asList(vertices.get(2l).getEdges(Direction.IN, "knows")).size(), 1);
assertEquals(asList(vertices.get(2l).getEdges(Direction.OUT, "created")).size(), 0);
assertEquals(asList(vertices.get(2l).getEdges(Direction.OUT)).size(), 0);
assertEquals(asList(vertices.get(2l).getEdges(Direction.IN)).size(), 1);
assertEquals(asList(vertices.get(3l).getEdges(Direction.OUT, "knows")).size(), 0);
assertEquals(asList(vertices.get(3l).getEdges(Direction.IN, "created")).size(), 3);
assertEquals(asList(vertices.get(3l).getEdges(Direction.OUT)).size(), 0);
assertEquals(asList(vertices.get(3l).getEdges(Direction.IN)).size(), 3);
assertEquals(asList(vertices.get(3l).getEdges(Direction.IN, "knows", "created")).size(), 3);
assertEquals(asList(vertices.get(4l).getEdges(Direction.BOTH, "created")).size(), 2);
assertEquals(asList(vertices.get(4l).getEdges(Direction.BOTH)).size(), 3);
assertEquals(asList(vertices.get(4l).getEdges(Direction.BOTH, "knows")).size(), 1);
assertEquals(asList(vertices.get(4l).getEdges(Direction.BOTH, "knows", "created")).size(), 3);
assertEquals(asList(vertices.get(4l).getEdges(Direction.BOTH, "blah")).size(), 0);
}
public void testVertexReuse() throws Exception {
FaunusVertex vertex = new FaunusVertex();
assertEquals(vertex.getId(), -1l);
assertFalse(vertex.pathEnabled);
assertFalse(vertex.getEdges(BOTH).iterator().hasNext());
vertex.addEdge(OUT, new FaunusEdge(1, 2, "knows"));
assertTrue(vertex.getEdges(BOTH).iterator().hasNext());
assertEquals(vertex.getPropertyKeys().size(), 0);
vertex.setProperty("name", "marko");
assertEquals(vertex.getProperty("name"), "marko");
assertEquals(vertex.getPropertyKeys().size(), 1);
vertex.reuse(10);
assertEquals(vertex.getId(), 10l);
assertFalse(vertex.getEdges(BOTH).iterator().hasNext());
assertEquals(vertex.getPropertyKeys().size(), 0);
assertNull(vertex.getProperty("name"));
assertFalse(vertex.pathEnabled);
vertex.enablePath(true);
assertTrue(vertex.pathEnabled);
assertEquals(vertex.getPaths().size(), 0);
vertex.reuse(220);
assertEquals(vertex.getId(), 220l);
assertFalse(vertex.getEdges(BOTH).iterator().hasNext());
assertEquals(vertex.getPropertyKeys().size(), 0);
assertNull(vertex.getProperty("name"));
assertTrue(vertex.pathEnabled);
vertex.startPath();
assertEquals(vertex.getPaths().size(), 1);
assertEquals(vertex.getPaths().get(0).size(), 1);
assertEquals(vertex.getPaths().get(0).get(0).getId(), 220);
vertex.reuse(34);
assertTrue(vertex.pathEnabled);
assertEquals(vertex.getPaths().size(), 0);
vertex.startPath();
assertEquals(vertex.getPaths().size(), 1);
assertEquals(vertex.getPaths().get(0).size(), 1);
assertEquals(vertex.getPaths().get(0).get(0).getId(), 34);
}
public void testNoPathsOnConstruction() throws Exception {
noPaths(generateGraph(ExampleGraph.TINKERGRAPH, new Configuration()), Vertex.class);
noPaths(generateGraph(ExampleGraph.TINKERGRAPH, new Configuration()), Edge.class);
}
public void testSequenceFileRepresentation() throws Exception {
final Configuration conf = new Configuration();
final SequenceFile.Reader reader = new SequenceFile.Reader(
FileSystem.get(conf), new Path(FaunusVertexTest.class.getResource("graph-of-the-gods-2.seq").toURI()), conf);
NullWritable key = NullWritable.get();
FaunusVertex value = new FaunusVertex();
final Map<Long, FaunusVertex> graph = new HashMap<Long, FaunusVertex>();
while (reader.next(key, value)) {
graph.put(value.getIdAsLong(), value);
value = new FaunusVertex();
}
identicalStructure(graph, ExampleGraph.GRAPH_OF_THE_GODS_2);
reader.close();
}
public void testLargeProperty() throws Exception {
String value = "a24$%~bU*!";
for (int i = 0; i < 18; i++) {
value = value + value;
}
// a 2.6 million length string == ~5 books worth of data
assertEquals(value.length(), 2621440);
FaunusVertex vertex1 = new FaunusVertex(1l);
vertex1.setProperty("name", value);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
vertex1.write(new DataOutputStream(bytes));
FaunusVertex vertex2 = new FaunusVertex(new DataInputStream(new ByteArrayInputStream(bytes.toByteArray())));
assertEquals(vertex2.getProperty("name"), value);
}
}