public List <VertexField> GetVerticesByIds(HashSet <string> vertexId, GraphViewCommand command, string partition, bool constructEdges = false) { const string NODE_ALIAS = "node"; var jsonQuery = new JsonQuery { NodeAlias = NODE_ALIAS, RawWhereClause = new WBooleanComparisonExpression { ComparisonType = BooleanComparisonType.Equals, FirstExpr = new WColumnReferenceExpression(NODE_ALIAS, DocumentDBKeywords.KW_EDGEDOC_IDENTIFIER), SecondExpr = new WValueExpression("null") } }; // SELECT node jsonQuery.AddSelectElement(NODE_ALIAS); jsonQuery.FlatProperties.Add(DocumentDBKeywords.KW_EDGEDOC_IDENTIFIER); jsonQuery.WhereConjunction(new WInPredicate( new WColumnReferenceExpression(NODE_ALIAS, GremlinKeyword.NodeID), vertexId.ToList()), BooleanBinaryExpressionType.And); if (partition != null) { jsonQuery.WhereConjunction(new WBooleanComparisonExpression { ComparisonType = BooleanComparisonType.Equals, FirstExpr = new WValueExpression($"{NODE_ALIAS}{command.Connection.GetPartitionPathIndexer()}", false), SecondExpr = new WValueExpression(partition, true) }, BooleanBinaryExpressionType.And); } jsonQuery.NodeProperties = new List <string> { "node", "*" }; jsonQuery.EdgeProperties = new List <string>(); IEnumerator <Tuple <VertexField, RawRecord> > queryResult = this.GetVerticesAndEdgesViaVertices(jsonQuery, command); List <VertexField> result = new List <VertexField>(); while (queryResult.MoveNext()) { VertexField vertex = queryResult.Current.Item1; result.Add(vertex); } if (constructEdges) { // TODO: need double check on JsonServer EdgeDocumentHelper.ConstructLazyAdjacencyList(command, EdgeType.Both, vertexId, new HashSet <string>()); } return(result); }
public IEnumerator <Tuple <VertexField, RawRecord> > GetVerticesAndEdgesViaVertices(JsonQuery vertexQuery, GraphViewCommand command) { IEnumerable <JObject> items = this.ExecuteQueryScript(vertexQuery); List <string> nodeProperties = new List <string>(vertexQuery.NodeProperties); List <string> edgeProperties = new List <string>(vertexQuery.EdgeProperties); string nodeAlias = nodeProperties[0]; // Skip i = 0, which is the (node.* as nodeAlias) field nodeProperties.RemoveAt(0); // // TODO: Refactor // string edgeAlias = null; bool isReverseAdj = false; bool isStartVertexTheOriginVertex = false; bool crossApplyEdgeOnServer = edgeProperties.Any(); if (crossApplyEdgeOnServer) { edgeAlias = edgeProperties[0]; isReverseAdj = bool.Parse(edgeProperties[1]); isStartVertexTheOriginVertex = bool.Parse(edgeProperties[2]); edgeProperties.RemoveAt(0); edgeProperties.RemoveAt(0); edgeProperties.RemoveAt(0); } // // Batch strategy: // - For "small" vertexes, they have been cross applied on the server side // - For "large" vertexes, just return the VertexField, the adjacency list decoder will // construct spilled adjacency lists in batch mode and cross apply edges after that // Func <VertexField, string, Tuple <VertexField, RawRecord> > makeCrossAppliedRecord = (vertexField, edgeId) => { Debug.Assert(vertexField != null); RawRecord nodeRecord = new RawRecord(); // // Fill node property field // foreach (string propertyName in nodeProperties) { FieldObject propertyValue = vertexField[propertyName]; nodeRecord.Append(propertyValue); } RawRecord edgeRecord = new RawRecord(edgeProperties.Count); EdgeField edgeField = ((AdjacencyListField)vertexField[isReverseAdj ? DocumentDBKeywords.KW_VERTEX_REV_EDGE : DocumentDBKeywords.KW_VERTEX_EDGE]) .GetEdgeField(edgeId, true); string startVertexId = vertexField.VertexId; AdjacencyListDecoder.FillMetaField(edgeRecord, edgeField, startVertexId, vertexField.Partition, isStartVertexTheOriginVertex, isReverseAdj); AdjacencyListDecoder.FillPropertyField(edgeRecord, edgeField, edgeProperties); nodeRecord.Append(edgeRecord); return(new Tuple <VertexField, RawRecord>(vertexField, nodeRecord)); }; Func <VertexField, Tuple <VertexField, RawRecord> > makeRawRecord = (vertexField) => { Debug.Assert(vertexField != null); RawRecord rawRecord = new RawRecord(); // // Fill node property field // foreach (string propertyName in nodeProperties) { FieldObject propertyValue = vertexField[propertyName]; rawRecord.Append(propertyValue); } return(new Tuple <VertexField, RawRecord>(vertexField, rawRecord)); }; HashSet <string> uniqueVertexIds = new HashSet <string>(); HashSet <string> uniqueEdgeIds = new HashSet <string>(); foreach (JObject dynamicItem in items) { JObject tmpVertexObject = (JObject)((JObject)dynamicItem)[nodeAlias]; string vertexId = (string)tmpVertexObject[DocumentDBKeywords.KW_DOC_ID]; if (crossApplyEdgeOnServer) { // Note: since vertex properties can be multi-valued, // a DocumentDB query needs a join clause in the FROM clause // to retrieve vertex property values, which may result in // the same vertex being returned multiple times. // We use the hash set uniqueVertexIds to ensure one vertex is // produced only once. if (EdgeDocumentHelper.IsBuildingTheAdjacencyListLazily( tmpVertexObject, isReverseAdj, this.Connection.UseReverseEdges) && uniqueVertexIds.Add(vertexId)) { VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, tmpVertexObject); yield return(makeRawRecord(vertexField)); } else // When the DocumentDB query crosses apply edges { JObject edgeObjct = (JObject)((JObject)dynamicItem)[edgeAlias]; string edgeId = (string)edgeObjct[DocumentDBKeywords.KW_EDGE_ID]; if (uniqueEdgeIds.Add(edgeId)) { VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, tmpVertexObject); yield return(makeCrossAppliedRecord(vertexField, edgeId)); } } } else { if (!uniqueVertexIds.Add(vertexId)) { continue; } VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, tmpVertexObject); yield return(makeRawRecord(vertexField)); } } }