From febdf3da7771f2bcf2d7c0c16ba154a16bf0a749 Mon Sep 17 00:00:00 2001 From: BingqingLyu Date: Fri, 31 Mar 2023 13:16:08 +0800 Subject: [PATCH 1/5] [IR Runtime] support filter by labels in auxilia --- .../ir/runtime/src/process/operator/map/get_v.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs b/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs index ac6934248b01..6eded15b81e8 100644 --- a/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs +++ b/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs @@ -146,6 +146,17 @@ impl FilterMapFunction for AuxiliaOperator { // e.g., for g.V().out().as("a").has("name", "marko"), we should compile as: // g.V().out().auxilia(as("a"))... where we give alias in auxilia, // then we set tag=None and alias="a" in auxilia + // 1. filter by labels. + if !self.query_params.labels.is_empty() && entry.label().is_some() { + if !self + .query_params + .labels + .contains(&entry.label().unwrap()) + { + return Ok(None); + } + } + // 2. further fetch properties, e.g., filter by columns. match entry.get_type() { EntryType::Vertex => { let graph = get_graph().ok_or(FnExecError::NullGraphError)?; From 06305bd738f71c91bf25c3e62925cc753210d0fa Mon Sep 17 00:00:00 2001 From: MeloYang Date: Fri, 31 Mar 2023 12:41:06 +0800 Subject: [PATCH 2/5] [Update]: update the logic about handling user given label table and schema inferred label table 1. if user given label table is empty, use the schema inferred label table, and vice versa 2. if the two tables are both not empty, use the intersection of the two tables --- .../executor/ir/core/src/glogue/pattern.rs | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/interactive_engine/executor/ir/core/src/glogue/pattern.rs b/interactive_engine/executor/ir/core/src/glogue/pattern.rs index abe096ee888f..552e0b3d2adc 100644 --- a/interactive_engine/executor/ir/core/src/glogue/pattern.rs +++ b/interactive_engine/executor/ir/core/src/glogue/pattern.rs @@ -647,18 +647,31 @@ fn generate_source_operator( pattern: &Pattern, source_extend: &ExactExtendStep, ) -> IrPatternResult { let source_vertex_id = source_extend.get_target_vertex_id(); - let source_vertex_table = generate_vertex_table(pattern, source_vertex_id)?; + let inferred_vertex_table = generate_vertex_table(pattern, source_vertex_id)?; // Fuse `source_vertex_label` into source, for efficiently scan let source_vertex_param = if let Some(mut vertex_param) = pattern .get_vertex_parameters(source_vertex_id)? .cloned() { - if source_vertex_table.len() > 0 { - vertex_param.tables = source_vertex_table; + // if user given vertex table is empty, using the inferred vertex table + // and vise versa + if vertex_param.tables.len() == 0 { + vertex_param.tables = inferred_vertex_table; + } + // if the two tables are both not empty + // intersect user given labels and inferred labels + else if inferred_vertex_table.len() > 0 { + let user_given_vertex_table = vertex_param.tables; + vertex_param.tables = vec![]; + for inferred_vertex_label in inferred_vertex_table { + if user_given_vertex_table.contains(&inferred_vertex_label) { + vertex_param.tables.push(inferred_vertex_label) + } + } } vertex_param } else { - query_params(source_vertex_table, vec![], None) + query_params(inferred_vertex_table, vec![], None) }; let source_scan = pb::Scan { scan_opt: 0, From b01868085bd4439ac5b836364614b695c71d1e9e Mon Sep 17 00:00:00 2001 From: BingqingLyu Date: Fri, 31 Mar 2023 13:53:48 +0800 Subject: [PATCH 3/5] [Update]: move the unsupported error for PathExpand ranging from 0 to the case when it is in Intersection --- .../executor/ir/core/src/glogue/pattern.rs | 11 ------ .../executor/ir/core/src/plan/physical.rs | 38 ++++++++++++++++--- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/interactive_engine/executor/ir/core/src/glogue/pattern.rs b/interactive_engine/executor/ir/core/src/glogue/pattern.rs index 552e0b3d2adc..6aac9019c93b 100644 --- a/interactive_engine/executor/ir/core/src/glogue/pattern.rs +++ b/interactive_engine/executor/ir/core/src/glogue/pattern.rs @@ -889,17 +889,6 @@ fn get_edge_expand_from_binder<'a, 'b>( ) -> IrPatternResult<&'a pb::EdgeExpand> { use pb::pattern::binder::Item as BinderItem; if let Some(BinderItem::Path(path_expand)) = binder.item.as_ref() { - let hop_range = path_expand - .hop_range - .as_ref() - .ok_or(ParsePbError::EmptyFieldError("pb::PathExpand::hop_range".to_string()))?; - if hop_range.lower < 1 { - // The path with range from 0 cannot be translated to oprs that can be intersected. - return Err(IrPatternError::Unsupported(format!( - "PathExpand in Pattern with lower range of {:?}", - hop_range.lower - )))?; - } let expand_base = path_expand .base .as_ref() diff --git a/interactive_engine/executor/ir/core/src/plan/physical.rs b/interactive_engine/executor/ir/core/src/plan/physical.rs index 41ec08ae83ad..ab43d224faa2 100644 --- a/interactive_engine/executor/ir/core/src/plan/physical.rs +++ b/interactive_engine/executor/ir/core/src/plan/physical.rs @@ -805,9 +805,17 @@ fn add_intersect_job_builder( if get_v.alias.is_none() || !get_v.alias.as_ref().unwrap().eq(intersect_tag) { Err(IrError::InvalidPattern("Cannot intersect on different tags".to_string()))? } + // If the first operator is PathExpand, pick its last expand out from the path let mut edge_expand = if let Some(Edge(edge_expand)) = first_opr.borrow().opr.opr.as_ref() { - Ok(edge_expand.clone()) + edge_expand.clone() } else if let Some(Path(path_expand)) = first_opr.borrow().opr.opr.as_ref() { + // Process path_expand as follows: + // 1. If path_expand range from 0, it is unsupported; + // 2. If it is path_expand(1,2), optimized as edge_expand; + // 3. Otherwise, translate path_expand(l,h) to path_expand(l-1, h-1) + endV() + edge_expand, + // and the last edge_expand is the one to intersect. + // Notice that if we have predicates for vertices in path_expand, or for the last vertex of path_expand, + // do the filtering after intersection. let mut path_expand = path_expand.clone(); let path_expand_base = path_expand .base @@ -828,37 +836,52 @@ fn add_intersect_job_builder( Err(IrError::Unsupported( "Edge Only PathExpand in Intersection's subplan has not been supported yet" .to_string(), - ))?; + ))? } + // Combine the params for the last vertex in path. + // That is, it should satisfy both params in `GetV` in PathExpand's ExpandBase, + // and the params in `EndV` following PathExpand. if let Some(path_get_v) = path_get_v_opt { get_v = combine_get_v_by_query_params(get_v, path_get_v); } + // pick the last edge expand out from the path expand let mut last_edge_expand = base_edge_expand.clone(); last_edge_expand.v_tag = None; let hop_range = path_expand .hop_range .as_mut() .ok_or(ParsePbError::EmptyFieldError("pb::PathExpand::hop_range".to_string()))?; + if hop_range.lower < 1 { + Err(IrError::Unsupported(format!( + "PathExpand in Intersection with lower range of {:?}", + hop_range.lower + )))? + } if hop_range.lower == 1 && hop_range.upper == 2 { + // optimized Path(1..2) to as EdgeExpand last_edge_expand.v_tag = path_expand.start_tag; } else { + // translate path_expand(l,h) to path_expand(l-1, h-1) + endV() + edge_expand, hop_range.lower -= 1; hop_range.upper -= 1; let mut end_v = pb::GetV::default(); end_v.opt = pb::get_v::VOpt::End as i32; + // build the path expansion path_expand.add_job_builder(builder, plan_meta)?; end_v.add_job_builder(builder, plan_meta)?; } - Ok(last_edge_expand) + last_edge_expand } else { Err(IrError::InvalidPattern( "First node of Intersection's subplan is neither EdgeExpand or PathExpand".to_string(), - )) - }?; + ))? + }; + // build the edge expansion + // the opt should be vertex because now only intersection on vertex is supported edge_expand.expand_opt = pb::edge_expand::ExpandOpt::Vertex as i32; edge_expand.alias = get_v.alias.clone(); edge_expand.add_job_builder(&mut sub_bldr, plan_meta)?; - + // vertex parameter after the intersection if let Some(params) = get_v.params.as_ref() { // the case that we need to further process getV's filter. if params.is_queryable() || !params.tables.is_empty() { @@ -870,13 +893,16 @@ fn add_intersect_job_builder( let sub_plan = sub_bldr.take_plan(); intersect_plans.push(sub_plan); } + // intersect builder.intersect(intersect_plans, intersect_tag.clone()); + // unfold the intersection let unfold = pb::Unfold { tag: Some(intersect_tag.clone()), alias: Some(intersect_tag.clone()), meta_data: None, }; unfold.add_job_builder(builder, plan_meta)?; + // add vertex filters if let Some(mut auxilia) = auxilia { auxilia.tag = Some(intersect_tag.clone()); builder.get_v(auxilia); From bfb0a166a4385921e7d0c0e6c32f66beb27fd7bd Mon Sep 17 00:00:00 2001 From: BingqingLyu Date: Fri, 31 Mar 2023 13:57:59 +0800 Subject: [PATCH 4/5] [IR Runtime] remove checking opt when GetV from Path, and treat all cases as to get the end vertex --- .../ir/runtime/src/process/operator/map/get_v.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs b/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs index 6eded15b81e8..ef1715045cb1 100644 --- a/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs +++ b/interactive_engine/executor/ir/runtime/src/process/operator/map/get_v.rs @@ -49,15 +49,10 @@ impl FilterMapFunction for GetVertexOperator { input.append(vertex, self.alias.clone()); Ok(Some(input)) } else if let Some(graph_path) = entry.as_graph_path() { - if let VOpt::End = self.opt { - let path_end = graph_path.get_path_end().clone(); - input.append(path_end, self.alias.clone()); - Ok(Some(input)) - } else { - Err(FnExecError::unsupported_error( - "Only support `GetV` with VOpt::End on a path entry", - ))? - } + // TODO: we do not check VOpt here, and we treat all cases as to get the end vertex of the path. + let path_end = graph_path.get_path_end().clone(); + input.append(path_end, self.alias.clone()); + Ok(Some(input)) } else { Err(FnExecError::unexpected_data_error( "Can only apply `GetV` (`Auxilia` instead) on an edge or path entry", From 89a6163cc837e12b47235604cfed21bc455f7b7b Mon Sep 17 00:00:00 2001 From: BingqingLyu Date: Fri, 31 Mar 2023 17:46:15 +0800 Subject: [PATCH 5/5] [bug fix]: fix the wrong label_id in modern_schema --- interactive_engine/executor/ir/core/resource/modern_schema.json | 2 +- .../executor/ir/core/resource/modern_schema_pk.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interactive_engine/executor/ir/core/resource/modern_schema.json b/interactive_engine/executor/ir/core/resource/modern_schema.json index ae69262ce267..289f67816f71 100644 --- a/interactive_engine/executor/ir/core/resource/modern_schema.json +++ b/interactive_engine/executor/ir/core/resource/modern_schema.json @@ -90,7 +90,7 @@ "name": "person" }, "dst": { - "id": 0, + "id": 1, "name": "software" } } diff --git a/interactive_engine/executor/ir/core/resource/modern_schema_pk.json b/interactive_engine/executor/ir/core/resource/modern_schema_pk.json index 3680160cb106..15908392809b 100644 --- a/interactive_engine/executor/ir/core/resource/modern_schema_pk.json +++ b/interactive_engine/executor/ir/core/resource/modern_schema_pk.json @@ -90,7 +90,7 @@ "name": "person" }, "dst": { - "id": 0, + "id": 1, "name": "software" } }