blob: e02d9227fed5a8bc8379baa8523e0a82c49d122a [file]
/*
* 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 "graphar/high-level/graph_reader.h"
#include <algorithm>
#include <unordered_set>
#include "arrow/array.h"
#include "graphar/api/arrow_reader.h"
#include "graphar/convert_to_arrow_type.h"
#include "graphar/label.h"
#include "graphar/types.h"
namespace graphar {
template <Type type>
Status CastToAny(std::shared_ptr<arrow::Array> array,
std::any& any) { // NOLINT
if (array->IsNull(0)) {
any = std::any();
return Status::OK();
}
using ArrayType = typename TypeToArrowType<type>::ArrayType;
auto column = std::dynamic_pointer_cast<ArrayType>(array);
any = column->GetView(0);
return Status::OK();
}
template <>
Status CastToAny<Type::STRING>(std::shared_ptr<arrow::Array> array,
std::any& any) { // NOLINT
using ArrayType = typename TypeToArrowType<Type::STRING>::ArrayType;
auto column = std::dynamic_pointer_cast<ArrayType>(array);
any = column->GetString(0);
return Status::OK();
}
Status TryToCastToAny(const std::shared_ptr<DataType>& type,
std::shared_ptr<arrow::Array> array,
std::any& any) { // NOLINT
switch (type->id()) {
case Type::BOOL:
return CastToAny<Type::BOOL>(array, any);
case Type::INT32:
return CastToAny<Type::INT32>(array, any);
case Type::INT64:
return CastToAny<Type::INT64>(array, any);
case Type::FLOAT:
return CastToAny<Type::FLOAT>(array, any);
case Type::DOUBLE:
return CastToAny<Type::DOUBLE>(array, any);
case Type::STRING:
return CastToAny<Type::STRING>(array, any);
case Type::DATE:
return CastToAny<Type::DATE>(array, any);
case Type::TIMESTAMP:
return CastToAny<Type::TIMESTAMP>(array, any);
default:
return Status::TypeError("Unsupported type.");
}
return Status::OK();
}
Vertex::Vertex(IdType id,
std::vector<VertexPropertyArrowChunkReader>& readers) // NOLINT
: id_(id) {
// get the first row of table
for (auto& reader : readers) {
GAR_ASSIGN_OR_RAISE_ERROR(auto chunk_table,
reader.GetChunk(graphar::GetChunkVersion::V1));
auto schema = chunk_table->schema();
for (int i = 0; i < schema->num_fields(); ++i) {
auto field = chunk_table->field(i);
if (field->type()->id() == arrow::Type::LIST) {
auto list_array = std::dynamic_pointer_cast<arrow::ListArray>(
chunk_table->column(i)->chunk(0));
list_properties_[field->name()] = list_array->value_slice(0);
} else {
auto type = DataType::ArrowDataTypeToDataType(field->type());
GAR_RAISE_ERROR_NOT_OK(TryToCastToAny(type,
chunk_table->column(i)->chunk(0),
properties_[field->name()]));
}
}
}
}
Result<bool> VertexIter::hasLabel(const std::string& label) noexcept {
std::shared_ptr<arrow::ChunkedArray> column(nullptr);
label_reader_.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE(auto chunk_table, label_reader_.GetLabelChunk());
column = util::GetArrowColumnByName(chunk_table, label);
if (column != nullptr) {
auto array = util::GetArrowArrayByChunkIndex(column, 0);
auto bool_array = std::dynamic_pointer_cast<arrow::BooleanArray>(array);
return bool_array->Value(0);
}
return Status::KeyError("label with name ", label,
" does not exist in the vertex.");
}
Result<std::vector<std::string>> VertexIter::label() noexcept {
std::shared_ptr<arrow::ChunkedArray> column(nullptr);
std::vector<std::string> vertex_label;
if (is_filtered_)
label_reader_.seek(filtered_ids_[cur_offset_]);
else
label_reader_.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE(auto chunk_table, label_reader_.GetLabelChunk());
for (auto label : labels_) {
column = util::GetArrowColumnByName(chunk_table, label);
if (column != nullptr) {
auto array = util::GetArrowArrayByChunkIndex(column, 0);
auto bool_array = std::dynamic_pointer_cast<arrow::BooleanArray>(array);
if (bool_array->Value(0)) {
vertex_label.push_back(label);
}
}
}
return vertex_label;
}
static inline bool IsValid(bool* state, int column_number) {
for (int i = 0; i < column_number; ++i) {
// AND case
if (!state[i])
return false;
// OR case
// if (state[i]) return true;
}
// AND case
return true;
// OR case
// return false;
}
Result<std::vector<IdType>> VerticesCollection::filter(
const std::vector<std::string>& filter_labels,
std::vector<IdType>* new_valid_chunk) {
std::vector<int> indices;
const int TOT_ROWS_NUM = vertex_num_;
const int CHUNK_SIZE = vertex_info_->GetChunkSize();
const int TOT_LABEL_NUM = labels_.size();
const int TESTED_LABEL_NUM = filter_labels.size();
std::vector<int> tested_label_ids;
for (const auto& filter_label : filter_labels) {
auto it = std::find(labels_.begin(), labels_.end(), filter_label);
if (it != labels_.end()) {
tested_label_ids.push_back(std::distance(labels_.begin(), it));
}
}
if (tested_label_ids.empty())
return Status::KeyError(
"query label"
" does not exist in the vertex.");
uint64_t* bitmap = new uint64_t[TOT_ROWS_NUM / 64 + 1];
memset(bitmap, 0, sizeof(uint64_t) * (TOT_ROWS_NUM / 64 + 1));
int total_count = 0;
int row_num;
if (is_filtered_) {
for (int chunk_idx : valid_chunk_) {
row_num = std::min(CHUNK_SIZE, TOT_ROWS_NUM - chunk_idx * CHUNK_SIZE);
std::string new_filename =
prefix_ + vertex_info_->GetPrefix() + "labels/chunk";
int count = read_parquet_file_and_get_valid_indices(
new_filename.c_str(), row_num, TOT_LABEL_NUM, TESTED_LABEL_NUM,
tested_label_ids, IsValid, chunk_idx, CHUNK_SIZE, &indices, bitmap,
QUERY_TYPE::INDEX);
if (count != 0 && new_valid_chunk != nullptr)
new_valid_chunk->emplace_back(static_cast<IdType>(chunk_idx));
}
} else {
for (int chunk_idx = 0; chunk_idx * CHUNK_SIZE < TOT_ROWS_NUM;
++chunk_idx) {
row_num = std::min(CHUNK_SIZE, TOT_ROWS_NUM - chunk_idx * CHUNK_SIZE);
std::string new_filename =
prefix_ + vertex_info_->GetPrefix() + "labels/chunk";
int count = read_parquet_file_and_get_valid_indices(
new_filename.c_str(), row_num, TOT_LABEL_NUM, TESTED_LABEL_NUM,
tested_label_ids, IsValid, chunk_idx, CHUNK_SIZE, &indices, bitmap,
QUERY_TYPE::INDEX);
if (count != 0)
valid_chunk_.emplace_back(static_cast<IdType>(chunk_idx));
}
}
// std::cout << "Total valid count: " << total_count << std::endl;
std::vector<int64_t> indices64;
for (int value : indices) {
indices64.push_back(static_cast<int64_t>(value));
}
delete[] bitmap;
return indices64;
}
Result<std::vector<IdType>> VerticesCollection::filter_by_acero(
const std::vector<std::string>& filter_labels) const {
std::vector<int> indices;
const int TOT_ROWS_NUM = vertex_num_;
const int CHUNK_SIZE = vertex_info_->GetChunkSize();
std::vector<int> tested_label_ids;
for (const auto& filter_label : filter_labels) {
auto it = std::find(labels_.begin(), labels_.end(), filter_label);
if (it != labels_.end()) {
tested_label_ids.push_back(std::distance(labels_.begin(), it));
}
}
int total_count = 0;
int row_num;
std::vector<std::shared_ptr<Expression>> filters;
std::shared_ptr<Expression> combined_filter = nullptr;
for (const auto& label : filter_labels) {
filters.emplace_back(
graphar::_Equal(graphar::_Property(label), graphar::_Literal(true)));
}
for (const auto& filter : filters) {
if (!combined_filter) {
combined_filter = graphar::_And(filter, filter);
} else {
combined_filter = graphar::_And(combined_filter, filter);
}
}
auto maybe_filter_reader = graphar::VertexPropertyArrowChunkReader::Make(
vertex_info_, labels_, prefix_, {});
auto filter_reader = maybe_filter_reader.value();
filter_reader->Filter(combined_filter);
for (int chunk_idx = 0; chunk_idx * CHUNK_SIZE < TOT_ROWS_NUM; ++chunk_idx) {
auto filter_result = filter_reader->GetLabelChunk();
auto filter_table = filter_result.value();
total_count += filter_table->num_rows();
filter_reader->next_chunk();
}
// std::cout << "Total valid count: " << total_count << std::endl;
std::vector<int64_t> indices64;
for (int value : indices) {
indices64.push_back(static_cast<int64_t>(value));
}
return indices64;
}
Result<std::vector<IdType>> VerticesCollection::filter(
const std::string& property_name,
std::shared_ptr<Expression> filter_expression,
std::vector<IdType>* new_valid_chunk) {
std::vector<int> indices;
const int TOT_ROWS_NUM = vertex_num_;
const int CHUNK_SIZE = vertex_info_->GetChunkSize();
int total_count = 0;
auto property_group = vertex_info_->GetPropertyGroup(property_name);
auto maybe_filter_reader = graphar::VertexPropertyArrowChunkReader::Make(
vertex_info_, property_group, prefix_, {});
auto filter_reader = maybe_filter_reader.value();
filter_reader->Filter(filter_expression);
std::vector<int64_t> indices64;
if (is_filtered_) {
for (int chunk_idx : valid_chunk_) {
// how to itetate valid_chunk_?
filter_reader->seek(chunk_idx * CHUNK_SIZE);
auto filter_result =
filter_reader->GetChunk(graphar::GetChunkVersion::V1);
auto filter_table = filter_result.value();
int count = filter_table->num_rows();
if (count != 0 && new_valid_chunk != nullptr) {
new_valid_chunk->emplace_back(static_cast<IdType>(chunk_idx));
// TODO(elssky): record indices
int kVertexIndexCol = filter_table->schema()->GetFieldIndex(
GeneralParams::kVertexIndexCol);
auto column_array = filter_table->column(kVertexIndexCol)->chunk(0);
auto int64_array =
std::static_pointer_cast<arrow::Int64Array>(column_array);
for (int64_t i = 0; i < int64_array->length(); ++i) {
if (!int64_array->IsNull(i)) {
indices64.push_back(int64_array->Value(i));
}
}
}
}
} else {
for (int chunk_idx = 0; chunk_idx * CHUNK_SIZE < TOT_ROWS_NUM;
++chunk_idx) {
auto filter_result =
filter_reader->GetChunk(graphar::GetChunkVersion::V1);
auto filter_table = filter_result.value();
int count = filter_table->num_rows();
filter_reader->next_chunk();
total_count += count;
if (count != 0) {
valid_chunk_.emplace_back(static_cast<IdType>(chunk_idx));
// TODO(elssky): record indices
int kVertexIndexCol = filter_table->schema()->GetFieldIndex(
GeneralParams::kVertexIndexCol);
auto column_array = filter_table->column(kVertexIndexCol)->chunk(0);
auto int64_array =
std::static_pointer_cast<arrow::Int64Array>(column_array);
for (int64_t i = 0; i < int64_array->length(); ++i) {
if (!int64_array->IsNull(i)) {
indices64.push_back(int64_array->Value(i));
}
}
}
}
}
// std::cout << "Total valid count: " << total_count << std::endl;
return indices64;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithLabel(
const std::string& filter_label,
const std::shared_ptr<GraphInfo>& graph_info, const std::string& type) {
auto prefix = graph_info->GetPrefix();
auto vertex_info = graph_info->GetVertexInfo(type);
auto labels = vertex_info->GetLabels();
auto vertices_collection =
std::make_shared<VerticesCollection>(vertex_info, prefix);
vertices_collection->filtered_ids_ =
vertices_collection->filter({filter_label}).value();
vertices_collection->is_filtered_ = true;
return vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithLabelbyAcero(
const std::string& filter_label,
const std::shared_ptr<GraphInfo>& graph_info, const std::string& type) {
auto prefix = graph_info->GetPrefix();
auto vertex_info = graph_info->GetVertexInfo(type);
auto labels = vertex_info->GetLabels();
auto vertices_collection =
std::make_shared<VerticesCollection>(vertex_info, prefix);
vertices_collection->filtered_ids_ =
vertices_collection->filter_by_acero({filter_label}).value();
vertices_collection->is_filtered_ = true;
return vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithLabel(
const std::string& filter_label,
const std::shared_ptr<VerticesCollection>& vertices_collection) {
auto new_vertices_collection = std::make_shared<VerticesCollection>(
vertices_collection->vertex_info_, vertices_collection->prefix_);
auto filtered_ids =
new_vertices_collection
->filter({filter_label}, &new_vertices_collection->valid_chunk_)
.value();
if (vertices_collection->is_filtered_) {
std::unordered_set<IdType> origin_set(
vertices_collection->filtered_ids_.begin(),
vertices_collection->filtered_ids_.end());
std::unordered_set<int> intersection;
for (int num : filtered_ids) {
if (origin_set.count(num)) {
intersection.insert(num);
}
}
filtered_ids =
std::vector<IdType>(intersection.begin(), intersection.end());
new_vertices_collection->is_filtered_ = true;
}
new_vertices_collection->filtered_ids_ = filtered_ids;
return new_vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithMultipleLabels(
const std::vector<std::string>& filter_labels,
const std::shared_ptr<GraphInfo>& graph_info, const std::string& type) {
auto prefix = graph_info->GetPrefix();
auto vertex_info = graph_info->GetVertexInfo(type);
auto labels = vertex_info->GetLabels();
auto vertices_collection =
std::make_shared<VerticesCollection>(vertex_info, prefix);
vertices_collection->filtered_ids_ =
vertices_collection->filter(filter_labels).value();
vertices_collection->is_filtered_ = true;
return vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithMultipleLabelsbyAcero(
const std::vector<std::string>& filter_labels,
const std::shared_ptr<GraphInfo>& graph_info, const std::string& type) {
auto prefix = graph_info->GetPrefix();
auto vertex_info = graph_info->GetVertexInfo(type);
auto labels = vertex_info->GetLabels();
auto vertices_collection =
std::make_shared<VerticesCollection>(vertex_info, prefix);
vertices_collection->filtered_ids_ =
vertices_collection->filter_by_acero(filter_labels).value();
vertices_collection->is_filtered_ = true;
return vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithMultipleLabels(
const std::vector<std::string>& filter_labels,
const std::shared_ptr<VerticesCollection>& vertices_collection) {
auto new_vertices_collection = std::make_shared<VerticesCollection>(
vertices_collection->vertex_info_, vertices_collection->prefix_);
auto filtered_ids =
vertices_collection
->filter(filter_labels, &new_vertices_collection->valid_chunk_)
.value();
if (vertices_collection->is_filtered_) {
std::unordered_set<IdType> origin_set(
vertices_collection->filtered_ids_.begin(),
vertices_collection->filtered_ids_.end());
std::unordered_set<int> intersection;
for (int num : filtered_ids) {
if (origin_set.count(num)) {
intersection.insert(num);
}
}
filtered_ids =
std::vector<IdType>(intersection.begin(), intersection.end());
new_vertices_collection->is_filtered_ = true;
}
new_vertices_collection->filtered_ids_ = filtered_ids;
return new_vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithProperty(
const std::string property_name, const graphar::util::Filter filter,
const std::shared_ptr<GraphInfo>& graph_info, const std::string& type) {
auto prefix = graph_info->GetPrefix();
auto vertex_info = graph_info->GetVertexInfo(type);
auto vertices_collection =
std::make_shared<VerticesCollection>(vertex_info, prefix);
vertices_collection->filtered_ids_ =
vertices_collection->filter(property_name, filter).value();
vertices_collection->is_filtered_ = true;
return vertices_collection;
}
Result<std::shared_ptr<VerticesCollection>>
VerticesCollection::verticesWithProperty(
const std::string property_name, const graphar::util::Filter filter,
const std::shared_ptr<VerticesCollection>& vertices_collection) {
auto new_vertices_collection = std::make_shared<VerticesCollection>(
vertices_collection->vertex_info_, vertices_collection->prefix_);
auto filtered_ids = vertices_collection
->filter(property_name, filter,
&new_vertices_collection->valid_chunk_)
.value();
if (vertices_collection->is_filtered_) {
std::unordered_set<IdType> origin_set(
vertices_collection->filtered_ids_.begin(),
vertices_collection->filtered_ids_.end());
std::unordered_set<int> intersection;
for (int num : filtered_ids) {
if (origin_set.count(num)) {
intersection.insert(num);
}
}
filtered_ids =
std::vector<IdType>(intersection.begin(), intersection.end());
new_vertices_collection->is_filtered_ = true;
}
new_vertices_collection->filtered_ids_ = filtered_ids;
return new_vertices_collection;
}
template <typename T>
Result<T> Vertex::property(const std::string& property) const {
if constexpr (std::is_final<T>::value) {
auto it = list_properties_.find(property);
if (it == list_properties_.end()) {
return Status::KeyError("The list property ", property,
" doesn't exist.");
}
auto array = std::dynamic_pointer_cast<
typename CTypeToArrowType<typename T::ValueType>::ArrayType>(
it->second);
const typename T::ValueType* values = array->raw_values();
return T(values, array->length());
} else {
if (properties_.find(property) == properties_.end()) {
return Status::KeyError("Property with name ", property,
" does not exist in the vertex.");
}
try {
if (!properties_.at(property).has_value())
return Status::TypeError("The value of the ", property, " is null.");
T ret = std::any_cast<T>(properties_.at(property));
return ret;
} catch (const std::bad_any_cast& e) {
return Status::TypeError("Any cast failed, the property type of ",
property, " is not matched ", e.what());
}
}
}
template <>
Result<Date> Vertex::property(const std::string& property) const {
if (properties_.find(property) == properties_.end()) {
return Status::KeyError("Property with name ", property,
" does not exist in the vertex.");
}
try {
if (!properties_.at(property).has_value())
return Status::TypeError("The value of the ", property, " is null.");
Date ret(std::any_cast<Date::c_type>(properties_.at(property)));
return ret;
} catch (const std::bad_any_cast& e) {
return Status::TypeError("Any cast failed, the property type of ", property,
" is not matched ", e.what());
}
}
template <>
Result<Timestamp> Vertex::property(const std::string& property) const {
if (properties_.find(property) == properties_.end()) {
return Status::KeyError("Property with name ", property,
" does not exist in the vertex.");
}
try {
if (!properties_.at(property).has_value())
return Status::TypeError("The value of the ", property, " is null.");
Timestamp ret(std::any_cast<Timestamp::c_type>(properties_.at(property)));
return ret;
} catch (const std::bad_any_cast& e) {
return Status::TypeError("Any cast failed, the property type of ", property,
" is not matched ", e.what());
}
}
template <>
Result<StringArray> Vertex::property(const std::string& property) const {
auto it = list_properties_.find(property);
if (it == list_properties_.end()) {
return Status::KeyError("The list property ", property, " doesn't exist.");
}
auto array = std::dynamic_pointer_cast<arrow::StringArray>(it->second);
return StringArray(array->raw_value_offsets(), array->raw_data(),
array->length());
}
Edge::Edge(
AdjListArrowChunkReader& adj_list_reader, // NOLINT
std::vector<AdjListPropertyArrowChunkReader>& property_readers) { // NOLINT
// get the first row of table
GAR_ASSIGN_OR_RAISE_ERROR(auto adj_list_chunk_table,
adj_list_reader.GetChunk());
src_id_ = std::dynamic_pointer_cast<arrow::Int64Array>(
adj_list_chunk_table->column(0)->chunk(0))
->GetView(0);
dst_id_ = std::dynamic_pointer_cast<arrow::Int64Array>(
adj_list_chunk_table->column(1)->chunk(0))
->GetView(0);
for (auto& reader : property_readers) {
// get the first row of table
GAR_ASSIGN_OR_RAISE_ERROR(auto chunk_table, reader.GetChunk());
auto schema = chunk_table->schema();
for (int i = 0; i < schema->num_fields(); ++i) {
auto field = chunk_table->field(i);
if (field->type()->id() == arrow::Type::LIST) {
auto list_array = std::dynamic_pointer_cast<arrow::ListArray>(
chunk_table->column(i)->chunk(0));
list_properties_[field->name()] = list_array->value_slice(0);
} else {
auto type = DataType::ArrowDataTypeToDataType(field->type());
GAR_RAISE_ERROR_NOT_OK(TryToCastToAny(type,
chunk_table->column(i)->chunk(0),
properties_[field->name()]));
}
}
}
}
template <typename T>
Result<T> Edge::property(const std::string& property) const {
if constexpr (std::is_final<T>::value) {
auto it = list_properties_.find(property);
if (it == list_properties_.end()) {
return Status::KeyError("The list property ", property,
" doesn't exist.");
}
auto array = std::dynamic_pointer_cast<
typename CTypeToArrowType<typename T::ValueType>::ArrayType>(
it->second);
const typename T::ValueType* values = array->raw_values();
return T(values, array->length());
} else {
if (properties_.find(property) == properties_.end()) {
return Status::KeyError("Property with name ", property,
" does not exist in the edge.");
}
try {
if (!properties_.at(property).has_value())
return Status::TypeError("The value of the ", property, " is null.");
T ret = std::any_cast<T>(properties_.at(property));
return ret;
} catch (const std::bad_any_cast& e) {
return Status::TypeError("Any cast failed, the property type of ",
property, " is not matched ", e.what());
}
}
}
template <>
Result<Date> Edge::property(const std::string& property) const {
if (properties_.find(property) == properties_.end()) {
return Status::KeyError("Property with name ", property,
" does not exist in the edge.");
}
try {
if (!properties_.at(property).has_value())
return Status::TypeError("The value of the ", property, " is null.");
Date ret(std::any_cast<Date::c_type>(properties_.at(property)));
return ret;
} catch (const std::bad_any_cast& e) {
return Status::TypeError("Any cast failed, the property type of ", property,
" is not matched ", e.what());
}
}
template <>
Result<Timestamp> Edge::property(const std::string& property) const {
if (properties_.find(property) == properties_.end()) {
return Status::KeyError("Property with name ", property,
" does not exist in the edge.");
}
try {
if (!properties_.at(property).has_value())
return Status::TypeError("The value of the ", property, " is null.");
Timestamp ret(std::any_cast<Timestamp::c_type>(properties_.at(property)));
return ret;
} catch (const std::bad_any_cast& e) {
return Status::TypeError("Any cast failed, the property type of ", property,
" is not matched ", e.what());
}
}
template <>
Result<StringArray> Edge::property(const std::string& property) const {
auto it = list_properties_.find(property);
if (it == list_properties_.end()) {
return Status::KeyError("The list property ", property, " doesn't exist.");
}
auto array = std::dynamic_pointer_cast<arrow::StringArray>(it->second);
return StringArray(array->raw_value_offsets(), array->raw_data(),
array->length());
}
#define INSTANTIATE_PROPERTY(T) \
template Result<T> Vertex::property<T>(const std::string& name) const; \
template Result<T> Edge::property<T>(const std::string& name) const;
INSTANTIATE_PROPERTY(bool)
INSTANTIATE_PROPERTY(const bool&)
INSTANTIATE_PROPERTY(int32_t)
INSTANTIATE_PROPERTY(const int32_t&)
INSTANTIATE_PROPERTY(Int32Array)
INSTANTIATE_PROPERTY(int64_t)
INSTANTIATE_PROPERTY(const int64_t&)
INSTANTIATE_PROPERTY(Int64Array)
INSTANTIATE_PROPERTY(float)
INSTANTIATE_PROPERTY(const float&)
INSTANTIATE_PROPERTY(FloatArray)
INSTANTIATE_PROPERTY(double)
INSTANTIATE_PROPERTY(const double&)
INSTANTIATE_PROPERTY(DoubleArray)
INSTANTIATE_PROPERTY(std::string)
INSTANTIATE_PROPERTY(const std::string&)
IdType EdgeIter::source() {
adj_list_reader_.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE_ERROR(auto chunk, adj_list_reader_.GetChunk());
auto src_column = chunk->column(0);
return std::dynamic_pointer_cast<arrow::Int64Array>(src_column->chunk(0))
->GetView(0);
}
IdType EdgeIter::destination() {
adj_list_reader_.seek(cur_offset_);
GAR_ASSIGN_OR_RAISE_ERROR(auto chunk, adj_list_reader_.GetChunk());
auto src_column = chunk->column(1);
return std::dynamic_pointer_cast<arrow::Int64Array>(src_column->chunk(0))
->GetView(0);
}
bool EdgeIter::first_src(const EdgeIter& from, IdType id) {
if (from.is_end())
return false;
// ordered_by_dest or unordered_by_dest
if (adj_list_type_ == AdjListType::ordered_by_dest ||
adj_list_type_ == AdjListType::unordered_by_dest) {
if (from.global_chunk_index_ >= chunk_end_) {
return false;
}
if (from.global_chunk_index_ == global_chunk_index_) {
cur_offset_ = from.cur_offset_;
} else if (from.global_chunk_index_ < chunk_begin_) {
this->to_begin();
} else {
global_chunk_index_ = from.global_chunk_index_;
cur_offset_ = from.cur_offset_;
vertex_chunk_index_ = from.vertex_chunk_index_;
this->refresh();
}
while (!this->is_end()) {
if (this->source() == id)
return true;
this->operator++();
}
return false;
}
// unordered_by_source
if (adj_list_type_ == AdjListType::unordered_by_source) {
IdType expect_chunk_index =
index_converter_->IndexPairToGlobalChunkIndex(id / src_chunk_size_, 0);
if (expect_chunk_index > chunk_end_)
return false;
if (from.global_chunk_index_ >= chunk_end_) {
return false;
}
bool need_refresh = false;
if (from.global_chunk_index_ == global_chunk_index_) {
cur_offset_ = from.cur_offset_;
} else if (from.global_chunk_index_ < chunk_begin_) {
this->to_begin();
} else {
global_chunk_index_ = from.global_chunk_index_;
cur_offset_ = from.cur_offset_;
vertex_chunk_index_ = from.vertex_chunk_index_;
need_refresh = true;
}
if (global_chunk_index_ < expect_chunk_index) {
global_chunk_index_ = expect_chunk_index;
cur_offset_ = 0;
vertex_chunk_index_ = id / src_chunk_size_;
need_refresh = true;
}
if (need_refresh)
this->refresh();
while (!this->is_end()) {
if (this->source() == id)
return true;
if (vertex_chunk_index_ > id / src_chunk_size_)
return false;
this->operator++();
}
return false;
}
// ordered_by_source
auto st = offset_reader_->seek(id);
if (!st.ok()) {
return false;
}
auto maybe_offset_chunk = offset_reader_->GetChunk();
if (!maybe_offset_chunk.status().ok()) {
return false;
}
auto offset_array =
std::dynamic_pointer_cast<arrow::Int64Array>(maybe_offset_chunk.value());
auto begin_offset = static_cast<IdType>(offset_array->Value(0));
auto end_offset = static_cast<IdType>(offset_array->Value(1));
if (begin_offset >= end_offset) {
return false;
}
auto vertex_chunk_index_of_id = offset_reader_->GetChunkIndex();
auto begin_global_index = index_converter_->IndexPairToGlobalChunkIndex(
vertex_chunk_index_of_id, begin_offset / chunk_size_);
auto end_global_index = index_converter_->IndexPairToGlobalChunkIndex(
vertex_chunk_index_of_id, end_offset / chunk_size_);
if (begin_global_index <= from.global_chunk_index_ &&
from.global_chunk_index_ <= end_global_index) {
if (begin_offset < from.cur_offset_ && from.cur_offset_ < end_offset) {
global_chunk_index_ = from.global_chunk_index_;
cur_offset_ = from.cur_offset_;
vertex_chunk_index_ = from.vertex_chunk_index_;
refresh();
return true;
} else if (from.cur_offset_ <= begin_offset) {
global_chunk_index_ = begin_global_index;
cur_offset_ = begin_offset;
vertex_chunk_index_ = vertex_chunk_index_of_id;
refresh();
return true;
} else {
return false;
}
} else if (from.global_chunk_index_ < begin_global_index) {
global_chunk_index_ = begin_global_index;
cur_offset_ = begin_offset;
vertex_chunk_index_ = vertex_chunk_index_of_id;
refresh();
return true;
} else {
return false;
}
}
bool EdgeIter::first_dst(const EdgeIter& from, IdType id) {
if (from.is_end())
return false;
// ordered_by_source or unordered_by_source
if (adj_list_type_ == AdjListType::ordered_by_source ||
adj_list_type_ == AdjListType::unordered_by_source) {
if (from.global_chunk_index_ >= chunk_end_) {
return false;
}
if (from.global_chunk_index_ == global_chunk_index_) {
cur_offset_ = from.cur_offset_;
} else if (from.global_chunk_index_ < chunk_begin_) {
this->to_begin();
} else {
global_chunk_index_ = from.global_chunk_index_;
cur_offset_ = from.cur_offset_;
vertex_chunk_index_ = from.vertex_chunk_index_;
this->refresh();
}
while (!this->is_end()) {
if (this->destination() == id)
return true;
this->operator++();
}
return false;
}
// unordered_by_dest
if (adj_list_type_ == AdjListType::unordered_by_dest) {
IdType expect_chunk_index =
index_converter_->IndexPairToGlobalChunkIndex(id / dst_chunk_size_, 0);
if (expect_chunk_index > chunk_end_)
return false;
if (from.global_chunk_index_ >= chunk_end_) {
return false;
}
bool need_refresh = false;
if (from.global_chunk_index_ == global_chunk_index_) {
cur_offset_ = from.cur_offset_;
} else if (from.global_chunk_index_ < chunk_begin_) {
this->to_begin();
} else {
global_chunk_index_ = from.global_chunk_index_;
cur_offset_ = from.cur_offset_;
vertex_chunk_index_ = from.vertex_chunk_index_;
need_refresh = true;
}
if (global_chunk_index_ < expect_chunk_index) {
global_chunk_index_ = expect_chunk_index;
cur_offset_ = 0;
vertex_chunk_index_ = id / dst_chunk_size_;
need_refresh = true;
}
if (need_refresh)
this->refresh();
while (!this->is_end()) {
if (this->destination() == id)
return true;
if (vertex_chunk_index_ > id / dst_chunk_size_)
return false;
this->operator++();
}
return false;
}
// ordered_by_dest
auto st = offset_reader_->seek(id);
if (!st.ok()) {
return false;
}
auto maybe_offset_chunk = offset_reader_->GetChunk();
if (!maybe_offset_chunk.status().ok()) {
return false;
}
auto offset_array =
std::dynamic_pointer_cast<arrow::Int64Array>(maybe_offset_chunk.value());
auto begin_offset = static_cast<IdType>(offset_array->Value(0));
auto end_offset = static_cast<IdType>(offset_array->Value(1));
if (begin_offset >= end_offset) {
return false;
}
auto vertex_chunk_index_of_id = offset_reader_->GetChunkIndex();
auto begin_global_index = index_converter_->IndexPairToGlobalChunkIndex(
vertex_chunk_index_of_id, begin_offset / chunk_size_);
auto end_global_index = index_converter_->IndexPairToGlobalChunkIndex(
vertex_chunk_index_of_id, end_offset / chunk_size_);
if (begin_global_index <= from.global_chunk_index_ &&
from.global_chunk_index_ <= end_global_index) {
if (begin_offset < from.cur_offset_ && from.cur_offset_ < end_offset) {
global_chunk_index_ = from.global_chunk_index_;
cur_offset_ = from.cur_offset_;
vertex_chunk_index_ = from.vertex_chunk_index_;
refresh();
return true;
} else if (from.cur_offset_ <= begin_offset) {
global_chunk_index_ = begin_global_index;
cur_offset_ = begin_offset;
vertex_chunk_index_ = vertex_chunk_index_of_id;
refresh();
return true;
} else {
return false;
}
} else if (from.global_chunk_index_ < begin_global_index) {
global_chunk_index_ = begin_global_index;
cur_offset_ = begin_offset;
vertex_chunk_index_ = vertex_chunk_index_of_id;
refresh();
return true;
} else {
return false;
}
}
Result<std::shared_ptr<EdgesCollection>> EdgesCollection::Make(
const std::shared_ptr<GraphInfo>& graph_info, const std::string& src_type,
const std::string& edge_type, const std::string& dst_type,
AdjListType adj_list_type, const IdType vertex_chunk_begin,
const IdType vertex_chunk_end) noexcept {
auto edge_info = graph_info->GetEdgeInfo(src_type, edge_type, dst_type);
if (!edge_info) {
return Status::KeyError("The edge ", src_type, " ", edge_type, " ",
dst_type, " doesn't exist.");
}
if (!edge_info->HasAdjacentListType(adj_list_type)) {
return Status::Invalid("The edge ", edge_type, " of adj list type ",
AdjListTypeToString(adj_list_type),
" doesn't exist.");
}
switch (adj_list_type) {
case AdjListType::ordered_by_source:
return std::make_shared<OBSEdgeCollection>(
edge_info, graph_info->GetPrefix(), vertex_chunk_begin,
vertex_chunk_end);
case AdjListType::ordered_by_dest:
return std::make_shared<OBDEdgesCollection>(
edge_info, graph_info->GetPrefix(), vertex_chunk_begin,
vertex_chunk_end);
case AdjListType::unordered_by_source:
return std::make_shared<UBSEdgesCollection>(
edge_info, graph_info->GetPrefix(), vertex_chunk_begin,
vertex_chunk_end);
case AdjListType::unordered_by_dest:
return std::make_shared<UBDEdgesCollection>(
edge_info, graph_info->GetPrefix(), vertex_chunk_begin,
vertex_chunk_end);
default:
return Status::Invalid("Unknown adj list type.");
}
return Status::OK();
}
} // namespace graphar