blob: a66bf37d7155b86304d87ac4d178ba30337eadfe [file] [log] [blame]
/*
* 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.
*/
#include <iostream>
#include "./util.h"
#include "graphar/api/high_level_reader.h"
#include <catch2/catch_test_macros.hpp>
namespace graphar {
TEST_CASE_METHOD(GlobalFixture, "Graph") {
// read file and construct graph info
std::string path =
test_data_dir + "/ldbc_sample/parquet/ldbc_sample.graph.yml";
auto maybe_graph_info = GraphInfo::Load(path);
REQUIRE(maybe_graph_info.status().ok());
auto graph_info = maybe_graph_info.value();
SECTION("VerticesCollection") {
// construct vertices collection
std::string type = "person", property = "firstName";
auto maybe_vertices_collection = VerticesCollection::Make(graph_info, type);
REQUIRE(!maybe_vertices_collection.has_error());
auto vertices = maybe_vertices_collection.value();
auto count = 0;
for (auto it = vertices->begin(); it != vertices->end(); ++it) {
// access data through iterator directly
std::cout << it.id() << ", id=" << it.property<int64_t>("id").value()
<< ", firstName="
<< it.property<std::string>("firstName").value() << std::endl;
// access data through vertex
auto vertex = *it;
std::cout << vertex.id()
<< ", id=" << vertex.property<int64_t>("id").value()
<< ", firstName="
<< vertex.property<std::string>("firstName").value()
<< std::endl;
// access data reference through vertex
REQUIRE(vertex.property<int64_t>("id").value() ==
vertex.property<const int64_t&>("id").value());
REQUIRE(vertex.property<std::string>("firstName").value() ==
vertex.property<const std::string&>("firstName").value());
REQUIRE(vertex.property<const std::string&>("id").has_error());
count++;
}
auto it_last = vertices->begin() + (count - 1);
std::cout << it_last.id()
<< ", id=" << it_last.property<int64_t>("id").value()
<< ", firstName="
<< it_last.property<std::string>("firstName").value()
<< std::endl;
auto it_begin = it_last + (1 - count);
auto it = vertices->begin();
it += (count - 1);
REQUIRE(it.id() == it_last.id());
REQUIRE(it.property<int64_t>("id").value() ==
it_last.property<int64_t>("id").value());
it += (1 - count);
REQUIRE(it.id() == it_begin.id());
REQUIRE(it.property<int64_t>("id").value() ==
it_begin.property<int64_t>("id").value());
}
SECTION("ListProperty") {
// read file and construct graph info
std::string path =
test_data_dir +
"/ldbc_sample/parquet/ldbc_sample_with_feature.graph.yml";
auto maybe_graph_info = GraphInfo::Load(path);
REQUIRE(maybe_graph_info.status().ok());
auto graph_info = maybe_graph_info.value();
std::string type = "person", list_property = "feature";
auto maybe_vertices_collection = VerticesCollection::Make(graph_info, type);
REQUIRE(!maybe_vertices_collection.has_error());
auto vertices = maybe_vertices_collection.value();
auto count = 0;
auto vertex_info = graph_info->GetVertexInfo(type);
auto data_type = vertex_info->GetPropertyType(list_property).value();
REQUIRE(data_type->id() == Type::LIST);
REQUIRE(data_type->value_type()->id() == Type::FLOAT);
if (data_type->id() == Type::LIST &&
data_type->value_type()->id() == Type::FLOAT) {
for (auto it = vertices->begin(); it != vertices->end(); ++it) {
auto vertex = *it;
auto float_array = vertex.property<FloatArray>(list_property).value();
for (size_t i = 0; i < float_array.size(); i++) {
REQUIRE(float_array[i] == static_cast<float>(vertex.id()) + i);
}
count++;
}
REQUIRE(count == 903);
}
}
SECTION("EdgesCollection") {
std::string src_type = "person", edge_type = "knows", dst_type = "person";
// iterate edges of vertex chunk 0
auto expect =
EdgesCollection::Make(graph_info, src_type, edge_type, dst_type,
AdjListType::ordered_by_source, 0, 1);
REQUIRE(!expect.has_error());
auto edges = expect.value();
auto end = edges->end();
size_t count = 0;
for (auto it = edges->begin(); it != end; ++it) {
// access data through iterator directly
std::cout << "src=" << it.source() << ", dst=" << it.destination() << " ";
// access data through edge
auto edge = *it;
REQUIRE(edge.source() == it.source());
REQUIRE(edge.destination() == it.destination());
std::cout << "creationDate="
<< edge.property<std::string>("creationDate").value()
<< std::endl;
// access data reference through edge
REQUIRE(edge.property<std::string>("creationDate").value() ==
edge.property<const std::string&>("creationDate").value());
REQUIRE(edge.property<const int64_t&>("creationDate").has_error());
count++;
}
std::cout << "edge_count=" << count << std::endl;
REQUIRE(edges->size() == count);
// iterate edges of vertex chunk [2, 4)
auto expect1 =
EdgesCollection::Make(graph_info, src_type, edge_type, dst_type,
AdjListType::ordered_by_dest, 2, 4);
REQUIRE(!expect1.has_error());
auto edges1 = expect1.value();
auto end1 = edges1->end();
size_t count1 = 0;
for (auto it = edges1->begin(); it != end1; ++it) {
count1++;
}
std::cout << "edge_count=" << count1 << std::endl;
REQUIRE(edges1->size() == count1);
// iterate all edges
auto expect2 =
EdgesCollection::Make(graph_info, src_type, edge_type, dst_type,
AdjListType::ordered_by_source);
REQUIRE(!expect2.has_error());
auto& edges2 = expect2.value();
auto end2 = edges2->end();
size_t count2 = 0;
for (auto it = edges2->begin(); it != end2; ++it) {
auto edge = *it;
std::cout << "src=" << edge.source() << ", dst=" << edge.destination()
<< std::endl;
count2++;
}
std::cout << "edge_count=" << count2 << std::endl;
REQUIRE(edges2->size() == count2);
// empty collection
auto expect3 =
EdgesCollection::Make(graph_info, src_type, edge_type, dst_type,
AdjListType::unordered_by_source, 5, 5);
REQUIRE(!expect2.has_error());
auto edges3 = expect3.value();
auto end3 = edges3->end();
size_t count3 = 0;
for (auto it = edges3->begin(); it != end3; ++it) {
count3++;
}
std::cout << "edge_count=" << count3 << std::endl;
REQUIRE(count3 == 0);
REQUIRE(edges3->size() == 0);
// invalid adjlist type
auto expect4 =
EdgesCollection::Make(graph_info, src_type, edge_type, dst_type,
AdjListType::unordered_by_dest);
REQUIRE(expect4.status().IsInvalid());
}
SECTION("ValidateProperty") {
// read file and construct graph info
std::string path = test_data_dir + "/neo4j/MovieGraph.graph.yml";
auto maybe_graph_info = GraphInfo::Load(path);
REQUIRE(maybe_graph_info.status().ok());
auto graph_info = maybe_graph_info.value();
// get vertices collection
std::string type = "Person", property = "born";
auto maybe_vertices_collection = VerticesCollection::Make(graph_info, type);
REQUIRE(!maybe_vertices_collection.has_error());
auto vertices = maybe_vertices_collection.value();
// the count of valid property value
auto count = 0;
for (auto it = vertices->begin(); it != vertices->end(); ++it) {
// get a vertex and access its data
auto vertex = *it;
// property not exists
REQUIRE_THROWS_AS(vertex.IsValid("bornn"), std::invalid_argument);
if (vertex.IsValid(property)) {
REQUIRE(vertex.property<int64_t>(property).value() != 0);
count++;
} else {
std::cout << "the property is not valid" << std::endl;
}
}
REQUIRE(count == 128);
auto last_invalid_vertex = *(vertices->end() + -1);
REQUIRE(last_invalid_vertex.property<int64_t>(property).has_error());
}
SECTION("EdgeIterator") {
std::string src_type = "person", edge_type = "knows", dst_type = "person";
auto expect =
EdgesCollection::Make(graph_info, src_type, edge_type, dst_type,
AdjListType::ordered_by_source);
REQUIRE(!expect.has_error());
auto edges = expect.value();
// Test iterator functionality
auto begin = edges->begin();
auto end = edges->end();
size_t count = 0;
// Iterate through first 2000 edges
for (auto it = begin; it != end; ++it) {
if (count >= 2000) {
break;
}
count++;
REQUIRE(it.source() >= 0);
REQUIRE(it.destination() >= 0);
REQUIRE(it.property<std::string>("creationDate").has_value());
}
REQUIRE(count == 2000);
// Test skipping and iterating next 2000 edges
auto begin2 = edges->begin();
size_t i = 0;
for (auto it = begin2; it != end; ++it, i++) {
if (i < 2000) {
continue;
}
if (i >= 4000) {
break;
}
count++;
REQUIRE(it.source() >= 0);
REQUIRE(it.destination() >= 0);
REQUIRE(it.property<std::string>("creationDate").has_value());
}
REQUIRE(count == 4000);
// Test skipping and iterating next 2000 edges
auto begin3 = edges->begin();
size_t j = 0;
for (auto it = begin3; it != end; ++it, j++) {
if (j < 4000) {
continue;
}
if (j >= 6000) {
break;
}
count++;
REQUIRE(it.source() >= 0);
REQUIRE(it.destination() >= 0);
REQUIRE(it.property<std::string>("creationDate").has_value());
}
REQUIRE(count == 6000);
// Test iterating remaining edges
auto begin4 = edges->begin();
size_t k = 0;
for (auto it = begin4; it != end; ++it, k++) {
if (k < 6000) {
continue;
}
count++;
REQUIRE(it.source() >= 0);
REQUIRE(it.destination() >= 0);
REQUIRE(it.property<std::string>("creationDate").has_value());
}
// Verify total count matches collection size
REQUIRE(count == edges->size());
std::cout << "Total edge_count=" << count << std::endl;
}
SECTION("DateType") {
std::string path_date =
test_data_dir + "/ldbc_sample/parquet/ldbc_sample_date.graph.yml";
auto maybe_graph_info_date = GraphInfo::Load(path_date);
REQUIRE(maybe_graph_info_date.status().ok());
auto graph_info_date = maybe_graph_info_date.value();
std::string src_type = "person", edge_type = "knows-date",
dst_type = "person";
auto expect =
EdgesCollection::Make(graph_info_date, src_type, edge_type, dst_type,
AdjListType::ordered_by_source);
REQUIRE(!expect.has_error());
auto edges = expect.value();
// Expected values for the first ten creationDate-date entries
int32_t expected_dates[10] = {14820, 15442, 14909, 15182, 15141,
15058, 15155, 15135, 15364, 15455};
size_t count = 0;
for (auto it = edges->begin(); it != edges->end() && count < 10;
++it, ++count) {
auto date_val = it.property<int32_t>("creationDate-date");
REQUIRE(date_val.has_value());
REQUIRE(date_val.value() == expected_dates[count]);
}
REQUIRE(count == 10);
std::cout << "DateType edge_count=" << count << std::endl;
}
SECTION("TimestampType") {
std::string path_timestamp =
test_data_dir + "/ldbc_sample/parquet/ldbc_sample_timestamp.graph.yml";
auto maybe_graph_info_timestamp = GraphInfo::Load(path_timestamp);
REQUIRE(maybe_graph_info_timestamp.status().ok());
auto graph_info_timestamp = maybe_graph_info_timestamp.value();
std::string src_type = "person", edge_type = "knows-timestamp",
dst_type = "person";
auto expect =
EdgesCollection::Make(graph_info_timestamp, src_type, edge_type,
dst_type, AdjListType::ordered_by_source);
REQUIRE(!expect.has_error());
auto edges = expect.value();
// Expected values for the first ten creationDate-timestamp entries
int64_t expected_timestamps[10] = {
1280503193298LL, 1334239018931LL, 1288146786288LL, 1311781394869LL,
1308223719623LL, 1301064563134LL, 1309416320777LL, 1307728039432LL,
1327492287348LL, 1335389465259LL};
size_t count = 0;
for (auto it = edges->begin(); it != edges->end() && count < 10;
++it, ++count) {
auto ts_val = it.property<int64_t>("creationDate-timestamp");
REQUIRE(ts_val.has_value());
REQUIRE(ts_val.value() == expected_timestamps[count]);
}
REQUIRE(count == 10);
std::cout << "TimestampType edge_count=" << count << std::endl;
}
}
} // namespace graphar