Skip to content

Commit

Permalink
Graph properties (Pometry#1079)
Browse files Browse the repository at this point in the history
* impl graph static properties graphql api

* add more filters

* add multiple layers filter to degree

* add property_history to node

* read files instead of directories from graphql server

---------

Co-authored-by: Shivam Kapoor <[email protected]>
  • Loading branch information
ricopinazo and shivam-880 authored Jun 29, 2023
1 parent 4fa687f commit c968832
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 29 deletions.
7 changes: 4 additions & 3 deletions raphtory-graphql/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ impl Data {
.into_iter()
.filter_map(|e| e.ok())
{
let p = entry.path().display().to_string();
if p.contains("graphdb_nr_shards") {
valid_paths.insert(p.strip_suffix("graphdb_nr_shards").unwrap().to_string());
let path = entry.path();
if path.is_file() {
valid_paths.insert(path.display().to_string());
}
}

Expand All @@ -35,6 +35,7 @@ impl Data {
let graphs: HashMap<String, Graph> = valid_paths
.into_iter()
.map(|path| {
println!("loading graph from {path}");
let graph = Graph::load_from_file(&path).expect("Unable to load from graph");
let maybe_graph_name = graph.static_property("name");

Expand Down
45 changes: 45 additions & 0 deletions raphtory-graphql/src/model/filters/edgefilter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::model::filters::primitives::{StringFilter, StringVecFilter};
use crate::model::graph::edge::Edge;
use crate::model::graph::node::Node;
use dynamic_graphql::InputObject;
use raphtory::db::view_api::{EdgeViewOps, VertexViewOps};

#[derive(InputObject)]
pub struct EdgeFilter {
node_names: Option<StringVecFilter>,
src: Option<StringFilter>,
dst: Option<StringFilter>,
layer_names: Option<StringVecFilter>,
}

impl EdgeFilter {
pub(crate) fn matches(&self, edge: &Edge) -> bool {
if let Some(names_filter) = &self.node_names {
let src = edge.ee.src().name();
let dst = edge.ee.dst().name();
if !names_filter.contains(&src) || !names_filter.contains(&dst) {
return false;
}
}

if let Some(name_filter) = &self.src {
if !name_filter.matches(&edge.ee.src().name()) {
return false;
}
}

if let Some(name_filter) = &self.dst {
if !name_filter.matches(&edge.ee.dst().name()) {
return false;
}
}

if let Some(name_filter) = &self.layer_names {
if !name_filter.contains(&edge.ee.layer_name()) {
return false;
}
}

true
}
}
1 change: 1 addition & 0 deletions raphtory-graphql/src/model/filters/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub(crate) mod nodefilter;
pub(crate) mod primitives;
pub(crate) mod property;
pub(crate) mod edgefilter;
9 changes: 8 additions & 1 deletion raphtory-graphql/src/model/filters/nodefilter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::model::filters::primitives::{NumberFilter, StringFilter};
use crate::model::filters::primitives::{NumberFilter, StringFilter, StringVecFilter};
use crate::model::filters::property::PropertyHasFilter;
use crate::model::graph::node::Node;
use dynamic_graphql::internal::{FromValue, InputTypeName, InputValueResult, Register, TypeName};
Expand All @@ -10,6 +10,7 @@ use std::borrow::Cow;

#[derive(InputObject)]
pub struct NodeFilter {
names: Option<StringVecFilter>,
name: Option<StringFilter>,
node_type: Option<StringFilter>,
in_degree: Option<NumberFilter>,
Expand All @@ -19,6 +20,12 @@ pub struct NodeFilter {

impl NodeFilter {
pub(crate) fn matches(&self, node: &Node) -> bool {
if let Some(names_filter) = &self.names {
if !names_filter.contains(&node.vv.name()) {
return false;
}
}

if let Some(name_filter) = &self.name {
if !name_filter.matches(&node.vv.name()) {
return false;
Expand Down
11 changes: 11 additions & 0 deletions raphtory-graphql/src/model/filters/primitives.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
use dynamic_graphql::InputObject;

#[derive(InputObject)]
pub(crate) struct StringVecFilter {
pub(crate) contains: Vec<String>,
}

impl StringVecFilter {
pub(crate) fn contains(&self, value: &str) -> bool {
self.contains.contains(&value.to_string())
}
}

#[derive(InputObject)]
pub(crate) struct StringFilter {
pub(crate) eq: Option<String>,
Expand Down
2 changes: 1 addition & 1 deletion raphtory-graphql/src/model/graph/edge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use raphtory::db::view_api::GraphViewOps;

#[derive(ResolvedObject)]
pub(crate) struct Edge {
ee: EdgeView<DynamicGraph>,
pub(crate) ee: EdgeView<DynamicGraph>,
}

impl<G: GraphViewOps + IntoDynamic> From<EdgeView<G>> for Edge {
Expand Down
62 changes: 58 additions & 4 deletions raphtory-graphql/src/model/graph/graph.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,48 @@
use crate::model::algorithm::Algorithms;
use crate::model::filters::edgefilter::EdgeFilter;
use crate::model::filters::nodefilter::NodeFilter;
use crate::model::graph::edge::Edge;
use crate::model::graph::node::Node;

use crate::model::graph::property::Property;
use dynamic_graphql::{ResolvedObject, ResolvedObjectFields};
use itertools::Itertools;
use raphtory::db::view_api::internal::{DynamicGraph, IntoDynamic};
use raphtory::db::view_api::{GraphViewOps, TimeOps, VertexViewOps};
use raphtory::db::view_api::{EdgeViewOps, GraphViewOps, TimeOps, VertexViewOps};

#[derive(ResolvedObject)]
pub(crate) struct GraphMeta {
name: String,
graph: DynamicGraph,
}

impl GraphMeta {
pub fn new(name: String, graph: DynamicGraph) -> Self {
Self { name, graph }
}
}

#[ResolvedObjectFields]
impl GraphMeta {
async fn name(&self) -> String {
self.name.clone()
}

async fn static_properties(&self) -> Vec<Property> {
self.graph
.static_properties()
.into_iter()
.map(|(k, v)| Property::new(k, v))
.collect()
}

async fn node_names(&self) -> Vec<String> {
self.graph
.vertices()
.into_iter()
.map(|v| v.name())
.collect_vec()
}
}

#[derive(ResolvedObject)]
pub(crate) struct GqlGraph {
Expand All @@ -27,6 +64,14 @@ impl GqlGraph {
w.into()
}

async fn static_properties(&self) -> Vec<Property> {
self.graph
.static_properties()
.into_iter()
.map(|(k, v)| Property::new(k, v))
.collect()
}

async fn nodes(&self, filter: Option<NodeFilter>) -> Vec<Node> {
match filter {
Some(filter) => self
Expand All @@ -40,8 +85,17 @@ impl GqlGraph {
}
}

async fn edges<'a>(&self) -> Vec<Edge> {
self.graph.edges().into_iter().map(|ev| ev.into()).collect()
async fn edges<'a>(&self, filter: Option<EdgeFilter>) -> Vec<Edge> {
match filter {
Some(filter) => self
.graph
.edges()
.into_iter()
.map(|ev| ev.into())
.filter(|ev| filter.matches(ev))
.collect(),
None => self.graph.edges().into_iter().map(|ev| ev.into()).collect(),
}
}

async fn node(&self, name: String) -> Option<Node> {
Expand Down
1 change: 1 addition & 0 deletions raphtory-graphql/src/model/graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub(crate) mod edge;
pub(crate) mod graph;
pub(crate) mod node;
pub(crate) mod property;
pub(crate) mod property_update;
45 changes: 31 additions & 14 deletions raphtory-graphql/src/model/graph/node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::model::filters::edgefilter::EdgeFilter;
use crate::model::graph::edge::Edge;
use crate::model::graph::property::Property;
use crate::model::graph::property_update::PropertyUpdate;
use async_graphql::Context;
use dynamic_graphql::{ResolvedObject, ResolvedObjectFields};
use itertools::Itertools;
Expand Down Expand Up @@ -60,6 +62,14 @@ impl Node {
Some(Property::new(name, prop))
}

async fn property_history(&self, name: String) -> Vec<PropertyUpdate> {
self.vv
.property_history(name)
.into_iter()
.map(|(time, prop)| PropertyUpdate::new(time, prop.to_string()))
.collect_vec()
}

async fn in_neighbours<'a>(&self, layer: Option<String>) -> Vec<Node> {
match layer {
None => self.vv.in_neighbours().iter().map(|vv| vv.into()).collect(),
Expand Down Expand Up @@ -101,13 +111,19 @@ impl Node {
}
}

async fn degree(&self, layer: Option<String>) -> usize {
match layer {
async fn degree(&self, layers: Option<Vec<String>>) -> usize {
match layers {
None => self.vv.degree(),
Some(layer) => match self.vv.layer(layer.as_str()) {
None => 0,
Some(vvv) => vvv.degree(),
},
Some(layers) => layers
.into_iter()
.map(|layer| {
let degree = match self.vv.layer(layer.as_str()) {
None => 0,
Some(vvv) => vvv.degree(),
};
return degree;
})
.sum(),
}
}

Expand Down Expand Up @@ -155,15 +171,16 @@ impl Node {
}
}

async fn edges(&self, layer: Option<String>) -> Vec<Edge> {
match layer {
async fn edges(&self, filter: Option<EdgeFilter>) -> Vec<Edge> {
match filter {
Some(filter) => self
.vv
.edges()
.into_iter()
.map(|ev| ev.into())
.filter(|ev| filter.matches(ev))
.collect(),
None => self.vv.edges().map(|ee| ee.clone().into()).collect(),
Some(layer) => match self.vv.layer(layer.as_str()) {
None => {
vec![]
}
Some(vvv) => vvv.edges().map(|ee| ee.clone().into()).collect(),
},
}
}

Expand Down
13 changes: 13 additions & 0 deletions raphtory-graphql/src/model/graph/property_update.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use dynamic_graphql::SimpleObject;

#[derive(SimpleObject)]
pub(crate) struct PropertyUpdate {
pub(crate) time: i64,
pub(crate) value: String,
}

impl PropertyUpdate {
pub fn new(time: i64, value: String) -> Self {
Self { time, value }
}
}
17 changes: 11 additions & 6 deletions raphtory-graphql/src/model/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::data::Data;
use crate::model::graph::graph::GqlGraph;
use crate::model::graph::graph::{GqlGraph, GraphMeta};
use async_graphql::Context;
use dynamic_graphql::{ResolvedObject, ResolvedObjectFields};
use itertools::Itertools;
use raphtory::db::view_api::internal::IntoDynamic;
use raphtory::db::view_api::GraphViewOps;

pub(crate) mod algorithm;
pub(crate) mod filters;
Expand All @@ -19,18 +21,21 @@ impl QueryRoot {
}

/// Returns a view including all events between `t_start` (inclusive) and `t_end` (exclusive)
async fn graph<'a>(ctx: &Context<'a>, name: &str) -> Option<GqlGraph> {
async fn graph<'a>(
ctx: &Context<'a>,
name: &str,
node_ids: &Option<Vec<i64>>,
) -> Option<GqlGraph> {
let data = ctx.data_unchecked::<Data>();
let g = data.graphs.get(name)?;
Some(g.clone().into())
}

async fn loaded_graphs<'a>(ctx: &Context<'a>) -> Vec<String> {
async fn graphs<'a>(ctx: &Context<'a>) -> Vec<GraphMeta> {
let data = ctx.data_unchecked::<Data>();
data.graphs
.keys()
.into_iter()
.map(|s| s.clone())
.iter()
.map(|(name, g)| GraphMeta::new(name.clone(), g.clone().into_dynamic()))
.collect_vec()
}
}

0 comments on commit c968832

Please sign in to comment.