// TODO: Batch upload for the DropEdge part
        internal override RawRecord DataModify(RawRecord record)
        {
            string vertexId = record[this._nodeIdIndex].ToValue;

            // Temporarily change
            DropEdgeOperator dropEdgeOp = new DropEdgeOperator(null, this.Connection, 0, 1);
            RawRecord        temp       = new RawRecord(2);

            VertexField vertex = this.Connection.VertexCache.GetVertexField(vertexId);

            // Save a copy of Edges _IDs & drop outgoing edges
            List <long> outEdgeOffsets = vertex.AdjacencyList.AllEdges.Select(e => e.Offset).ToList();

            foreach (long outEdgeOffset in outEdgeOffsets)
            {
                temp.fieldValues[0] = new StringField(vertexId);
                temp.fieldValues[1] = new StringField(outEdgeOffset.ToString());
                dropEdgeOp.DataModify(temp);
            }

            AdjacencyListField revAdjacencyListField = Connection.UseReverseEdges
                                                       ? vertex.RevAdjacencyList
                                                       : EdgeDocumentHelper.GetReverseAdjacencyListOfVertex(Connection, vertexId);
            // Save a copy of incoming Edges <srcVertexId, edgeOffsetInSrcVertex> & drop them
            List <Tuple <string, long> > inEdges = revAdjacencyListField.AllEdges.Select(
                e => new Tuple <string, long>(e.OutV, e.Offset)).ToList();

            foreach (var inEdge in inEdges)
            {
                temp.fieldValues[0] = new StringField(inEdge.Item1);            // srcVertexId
                temp.fieldValues[1] = new StringField(inEdge.Item2.ToString()); // edgeOffsetInSrcVertex
                dropEdgeOp.DataModify(temp);
            }

            // Delete the node-document!
#if DEBUG
            JObject vertexObject = this.Connection.RetrieveDocumentById(vertexId);
            Debug.Assert(vertexObject != null);
            Debug.Assert(vertexObject["_edge"] is JArray);
            Debug.Assert(((JArray)vertexObject["_edge"]).Count == 0);
            Debug.Assert(vertexObject["_reverse_edge"] is JArray);
            Debug.Assert(((JArray)vertexObject["_reverse_edge"]).Count == 0);
#endif
            // NOTE: for vertex document, id = _partition
            this.Connection.ReplaceOrDeleteDocumentAsync(vertexId, null, vertexId).Wait();

            // Update VertexCache
            this.Connection.VertexCache.TryRemoveVertexField(vertexId);

            return(null);
        }
        internal override RawRecord DataModify(RawRecord record)
        {
            string srcId      = record[this._srcIdIndex].ToValue;
            long   edgeOffset = long.Parse(record[this._edgeOffsetIndex].ToValue);

            JObject srcEdgeObject;
            string  srcEdgeDocId, sinkEdgeDocId;
            JObject srcVertexObject = this.Connection.RetrieveDocumentById(srcId);

            EdgeDocumentHelper.FindEdgeBySourceAndOffset(
                this.Connection, srcVertexObject, srcId, edgeOffset, false,
                out srcEdgeObject, out srcEdgeDocId);
            if (srcEdgeObject == null)
            {
                //TODO: Check is this condition alright?
                return(null);
            }

            string  sinkId = (string)srcEdgeObject["_sinkV"];
            JObject sinkVertexObject;

            if (!string.Equals(sinkId, srcId))
            {
                sinkVertexObject = this.Connection.RetrieveDocumentById(sinkId);
                JObject sinkEdgeObject;
                EdgeDocumentHelper.FindEdgeBySourceAndOffset(
                    this.Connection, sinkVertexObject, srcId, edgeOffset, true,
                    out sinkEdgeObject, out sinkEdgeDocId);
            }
            else
            {
                sinkVertexObject = srcVertexObject;  // NOTE: Must not use DeepClone() here!
                sinkEdgeDocId    = srcEdgeDocId;
            }

            Dictionary <string, Tuple <JObject, string> > uploadDocuments = new Dictionary <string, Tuple <JObject, string> >();

            EdgeDocumentHelper.RemoveEdge(uploadDocuments, this.Connection, srcEdgeDocId, srcVertexObject, false, srcId, edgeOffset);
            EdgeDocumentHelper.RemoveEdge(uploadDocuments, this.Connection, sinkEdgeDocId, sinkVertexObject, true, srcId, edgeOffset);
            this.Connection.ReplaceOrDeleteDocumentsAsync(uploadDocuments).Wait();


            VertexField srcVertexField  = this.Connection.VertexCache.GetVertexField(srcId, srcVertexObject);
            VertexField sinkVertexField = this.Connection.VertexCache.GetVertexField(sinkId, sinkVertexObject);

            srcVertexField.AdjacencyList.RemoveEdgeField(srcId, edgeOffset);
            sinkVertexField.RevAdjacencyList.RemoveEdgeField(srcId, edgeOffset);

            return(null);
        }
        internal override RawRecord DataModify(RawRecord record)
        {
            long   edgeOffset  = long.Parse(record[this._edgeOffsetIndex].ToValue);
            string srcVertexId = record[this._srcVertexIdIndex].ToValue;

            JObject srcVertexObject = this.Connection.RetrieveDocumentById(srcVertexId);
            string  outEdgeDocId;
            JObject outEdgeObject;

            EdgeDocumentHelper.FindEdgeBySourceAndOffset(
                this.Connection, srcVertexObject, srcVertexId, edgeOffset, false,
                out outEdgeObject, out outEdgeDocId);
            if (outEdgeObject == null)
            {
                // TODO: Is there something wrong?
                Debug.WriteLine($"[UpdateEdgePropertiesOperator] The edge does not exist: vertexId = {srcVertexId}, edgeOffset = {edgeOffset}");
                return(null);
            }

            string  sinkVertexId = (string)outEdgeObject["_sinkV"];
            JObject sinkVertexObject;
            string  inEdgeDocId;
            JObject inEdgeObject;

            if (sinkVertexId.Equals(srcVertexId))
            {
                sinkVertexObject = srcVertexObject;  // NOTE: Must not use DeepClone() here!
            }
            else
            {
                sinkVertexObject = this.Connection.RetrieveDocumentById(sinkVertexId);
            }
            EdgeDocumentHelper.FindEdgeBySourceAndOffset(
                this.Connection, sinkVertexObject, srcVertexId, edgeOffset, true,
                out inEdgeObject, out inEdgeDocId);

            VertexField srcVertexField  = this.Connection.VertexCache.GetVertexField(srcVertexId);
            VertexField sinkVertexField = this.Connection.VertexCache.GetVertexField(sinkVertexId);
            EdgeField   outEdgeField    = srcVertexField.AdjacencyList.GetEdgeField(srcVertexId, edgeOffset);
            EdgeField   inEdgeField     = sinkVertexField.RevAdjacencyList.GetEdgeField(srcVertexId, edgeOffset);

            // Drop all non-reserved properties
            if (this.PropertiesToBeUpdated.Count == 1 &&
                !this.PropertiesToBeUpdated[0].Item1.SingleQuoted &&
                this.PropertiesToBeUpdated[0].Item1.Value.Equals("*", StringComparison.OrdinalIgnoreCase) &&
                !this.PropertiesToBeUpdated[0].Item2.SingleQuoted &&
                this.PropertiesToBeUpdated[0].Item2.Value.Equals("null", StringComparison.OrdinalIgnoreCase))
            {
                List <string> toBeDroppedProperties = GraphViewJsonCommand.DropAllEdgeProperties(outEdgeObject);
                foreach (var propertyName in toBeDroppedProperties)
                {
                    outEdgeField.EdgeProperties.Remove(propertyName);
                }

                toBeDroppedProperties = GraphViewJsonCommand.DropAllEdgeProperties(inEdgeObject);
                foreach (var propertyName in toBeDroppedProperties)
                {
                    inEdgeField.EdgeProperties.Remove(propertyName);
                }
            }
            else
            {
                foreach (Tuple <WValueExpression, WValueExpression, int> tuple in this.PropertiesToBeUpdated)
                {
                    WValueExpression keyExpression   = tuple.Item1;
                    WValueExpression valueExpression = tuple.Item2;

                    if (this.Mode == UpdatePropertyMode.Set)
                    {
                        // Modify edgeObject (update the edge property)
                        JProperty updatedProperty = GraphViewJsonCommand.UpdateProperty(outEdgeObject, keyExpression, valueExpression);
                        // Update VertexCache
                        if (updatedProperty == null)
                        {
                            outEdgeField.EdgeProperties.Remove(keyExpression.Value);
                        }
                        else
                        {
                            outEdgeField.UpdateEdgeProperty(updatedProperty, outEdgeField);
                        }

                        // Modify edgeObject (update the edge property)
                        updatedProperty = GraphViewJsonCommand.UpdateProperty(inEdgeObject, keyExpression, valueExpression);
                        // Update VertexCache
                        if (updatedProperty == null)
                        {
                            inEdgeField.EdgeProperties.Remove(keyExpression.Value);
                        }
                        else
                        {
                            inEdgeField.UpdateEdgeProperty(updatedProperty, inEdgeField);
                        }
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
            }

            // Interact with DocDB to update the property
            EdgeDocumentHelper.UpdateEdgeProperty(this.Connection, srcVertexObject, outEdgeDocId, false, outEdgeObject);
            EdgeDocumentHelper.UpdateEdgeProperty(this.Connection, sinkVertexObject, inEdgeDocId, true, inEdgeObject);


            //
            // Drop edge property
            //
            if (this.PropertiesToBeUpdated.Any(t => t.Item2 == null))
            {
                return(null);
            }
            return(record);
        }
        internal override RawRecord DataModify(RawRecord record)
        {
            VertexField srcVertexField  = _srcFunction.Evaluate(record) as VertexField;
            VertexField sinkVertexField = _sinkFunction.Evaluate(record) as VertexField;

            if (srcVertexField == null || sinkVertexField == null)
            {
                return(null);
            }

            string srcId  = srcVertexField["id"].ToValue;
            string sinkId = sinkVertexField["id"].ToValue;
            //string srcJsonDocument = srcVertexField.JsonDocument;
            //string sinkJsonDocument = sinkVertexField.JsonDocument;

            JObject srcVertexObject = this.Connection.RetrieveDocumentById(srcId);
            JObject sinkVertexObject;

            if (srcId.Equals(sinkId))
            {
                // MUST not use JObject.DeepClone() here!
                sinkVertexObject = srcVertexObject;
            }
            else
            {
                sinkVertexObject = this.Connection.RetrieveDocumentById(sinkId);
            }

            //VertexField srcVertexField = (srcFieldObject as VertexField)
            //                              ?? Connection.VertexCache.GetVertexField(srcId, srcVertexObject);
            //VertexField sinkVertexField = (sinkFieldObject as VertexField)
            //                               ?? Connection.VertexCache.GetVertexField(sinkId, sinkVertexObject);



            //
            // Interact with DocDB and add the edge
            // - For a small-degree vertex (now filled into one document), insert the edge in-place
            //     - If the upload succeeds, done!
            //     - If the upload fails with size-limit-exceeded(SLE), put either incoming or outgoing edges into a seperate document
            // - For a large-degree vertex (already spilled)
            //     - Update either incoming or outgoing edges in the seperate edge-document
            //     - If the upload fails with SLE, create a new document to store the edge, and update the vertex document
            //
            JObject outEdgeObject, inEdgeObject;
            string  outEdgeDocID, inEdgeDocID;

            EdgeDocumentHelper.InsertEdgeAndUpload(this.Connection,
                                                   srcId, sinkId,
                                                   srcVertexField, sinkVertexField, this._edgeJsonObject,
                                                   srcVertexObject, sinkVertexObject,
                                                   out outEdgeObject, out outEdgeDocID,
                                                   out inEdgeObject, out inEdgeDocID);

            //
            // Update vertex's adjacency list and reverse adjacency list (in vertex field)
            //
            EdgeField outEdgeField = EdgeField.ConstructForwardEdgeField(srcId, srcVertexField["label"]?.ToValue, outEdgeDocID, outEdgeObject);
            EdgeField inEdgeField  = EdgeField.ConstructBackwardEdgeField(sinkId, sinkVertexField["label"]?.ToValue, inEdgeDocID, inEdgeObject);

            srcVertexField.AdjacencyList.AddEdgeField(srcId, outEdgeField.Offset, outEdgeField);
            sinkVertexField.RevAdjacencyList.AddEdgeField(srcId, inEdgeField.Offset, inEdgeField);


            // Construct the newly added edge's RawRecord
            RawRecord result = new RawRecord();

            // source, sink, other, offset, *
            result.Append(new StringField(srcId));
            result.Append(new StringField(sinkId));
            result.Append(new StringField(_otherVTag == 0 ? srcId : sinkId));
            result.Append(new StringField(outEdgeObject["_offset"].ToString()));
            result.Append(outEdgeField);

            for (int i = GraphViewReservedProperties.ReservedEdgeProperties.Count; i < _edgeProperties.Count; i++)
            {
                FieldObject fieldValue = outEdgeField[_edgeProperties[i]];
                result.Append(fieldValue);
            }

            return(result);
        }
예제 #5
0
        internal static string ToGraphSON(List <RawRecord> results, GraphViewConnection connection)
        {
            StringBuilder    finalGraphSonResult            = new StringBuilder("[");
            HashSet <string> batchIdSet                     = new HashSet <string>();
            Dictionary <int, VertexField> batchGraphSonDict = new Dictionary <int, VertexField>();

            StringBuilder notBatchedGraphSonResult = new StringBuilder();
            bool          firstEntry = true;

            foreach (RawRecord record in results)
            {
                if (firstEntry)
                {
                    firstEntry = false;
                }
                else
                {
                    notBatchedGraphSonResult.Append(", ");
                }
                FieldObject field = record[0];

                VertexField vertexField = field as VertexField;
                if (vertexField != null &&
                    (!vertexField.AdjacencyList.HasBeenFetched || !vertexField.RevAdjacencyList.HasBeenFetched))
                {
                    string vertexId = vertexField[GraphViewKeywords.KW_DOC_ID].ToValue;
                    batchIdSet.Add(vertexId);
                    batchGraphSonDict.Add(notBatchedGraphSonResult.Length, vertexField);
                    continue;
                }

                notBatchedGraphSonResult.Append(field.ToGraphSON());
            }

            if (batchIdSet.Any())
            {
                EdgeDocumentHelper.ConstructSpilledAdjListsOrVirtualRevAdjListsOfVertices(connection, batchIdSet);

                int startIndex = 0;
                foreach (KeyValuePair <int, VertexField> kvp in batchGraphSonDict)
                {
                    int         insertedPosition = kvp.Key;
                    int         length           = insertedPosition - startIndex;
                    VertexField vertexField      = kvp.Value;

                    finalGraphSonResult.Append(notBatchedGraphSonResult.ToString(startIndex, length));
                    finalGraphSonResult.Append(vertexField.ToGraphSON());
                    startIndex = insertedPosition;
                }

                finalGraphSonResult.Append(notBatchedGraphSonResult.ToString(startIndex,
                                                                             notBatchedGraphSonResult.Length - startIndex));
            }
            else
            {
                finalGraphSonResult.Append(notBatchedGraphSonResult.ToString());
            }

            finalGraphSonResult.Append("]");
            return(finalGraphSonResult.ToString());
        }
예제 #6
0
        public void Upload(GraphViewCommand command)
        {
            if (this.isAddE && this.isDropE)
            {
                return;
            }
            else if (this.isAddE)
            {
                string outEdgeDocId;
                EdgeDocumentHelper.InsertEdgeObjectInternal(command, this.srcVertexField.VertexJObject, this.srcVertexField,
                                                            this.outEdgeField.EdgeJObject, false, out outEdgeDocId);
                this.outEdgeField.EdgeDocID = outEdgeDocId;

                if (this.UseReverseEdges)
                {
                    string inEdgeDocId;
                    EdgeDocumentHelper.InsertEdgeObjectInternal(command, this.sinkVertexField.VertexJObject, this.sinkVertexField,
                                                                this.inEdgeField.EdgeJObject, true, out inEdgeDocId);
                    this.inEdgeField.EdgeDocID = inEdgeDocId;
                }
            }
            else if (this.isDropE)
            {
                string edgeId = outEdgeField.EdgeId;
                string srcId  = outEdgeField.OutV;
                string sinkId = outEdgeField.InV;

                JObject outEdgeObject;
                string  outEdgeDocId;
                EdgeDocumentHelper.FindEdgeBySourceAndEdgeId(
                    command, this.srcVertexField.VertexJObject, srcId, edgeId, false,
                    out outEdgeObject, out outEdgeDocId);

                if (outEdgeObject == null)
                {
                    // something wrong. the edge that we want to drop does not exist in db
                    return;
                }

                string inEdgeDocId = null;
                if (this.UseReverseEdges)
                {
                    if (!string.Equals(sinkId, srcId))
                    {
                        JObject dummySinkEdgeObject;
                        EdgeDocumentHelper.FindEdgeBySourceAndEdgeId(
                            command, this.sinkVertexField.VertexJObject, srcId, edgeId, true,
                            out dummySinkEdgeObject, out inEdgeDocId);
                    }
                    else
                    {
                        Debug.Assert(object.ReferenceEquals(this.sinkVertexField, this.srcVertexField));
                        Debug.Assert(this.sinkVertexField.VertexJObject == this.srcVertexField.VertexJObject);
                        inEdgeDocId = outEdgeDocId;
                    }
                }

                // <docId, <docJson, partition>>
                Dictionary <string, Tuple <JObject, string> > uploadDocuments = new Dictionary <string, Tuple <JObject, string> >();
                EdgeDocumentHelper.RemoveEdge(uploadDocuments, command, outEdgeDocId,
                                              this.srcVertexField, false, srcId, edgeId);
                if (this.UseReverseEdges)
                {
                    EdgeDocumentHelper.RemoveEdge(uploadDocuments, command, inEdgeDocId,
                                                  this.sinkVertexField, true, srcId, edgeId);
                }
                command.Connection.ReplaceOrDeleteDocumentsAsync(uploadDocuments, command).Wait();
            }
            else if (this.deltaProperties.Count > 0)
            {
                string edgeId = outEdgeField.EdgeId;
                string srcId  = outEdgeField.OutV;
                string sinkId = outEdgeField.InV;

                JObject outEdgeObject;
                string  outEdgeDocId;
                EdgeDocumentHelper.FindEdgeBySourceAndEdgeId(
                    command, this.srcVertexField.VertexJObject, srcId, edgeId, false,
                    out outEdgeObject, out outEdgeDocId);

                if (outEdgeObject == null)
                {
                    // something wrong. the edge that we want to update does not exist in db
                    return;
                }

                string inEdgeDocId = null;
                if (this.UseReverseEdges)
                {
                    if (!string.Equals(sinkId, srcId))
                    {
                        JObject inEdgeObject;
                        EdgeDocumentHelper.FindEdgeBySourceAndEdgeId(
                            command, this.sinkVertexField.VertexJObject, srcId, edgeId, true,
                            out inEdgeObject, out inEdgeDocId);
                    }
                    else
                    {
                        Debug.Assert(object.ReferenceEquals(this.sinkVertexField, this.srcVertexField));
                        Debug.Assert(this.sinkVertexField.VertexJObject == this.srcVertexField.VertexJObject);
                        inEdgeDocId = outEdgeDocId;
                    }
                }

                // Interact with DocDB to update the property
                EdgeDocumentHelper.UpdateEdgeProperty(command, this.srcVertexField.VertexJObject, outEdgeDocId, false,
                                                      this.outEdgeField.EdgeJObject);
                if (this.UseReverseEdges)
                {
                    EdgeDocumentHelper.UpdateEdgeProperty(command, this.sinkVertexField.VertexJObject, inEdgeDocId, true,
                                                          this.inEdgeField.EdgeJObject);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// For every vertex in the vertexIdSet, retrieve their spilled edge documents to construct their forward or backward
        /// adjacency list.
        /// When connection.useReverseEdge is false, this method will retrieve all the forward edge documents whose sink
        /// is the target vertex to build a virtual reverse adjacency list.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="edgeType"></param>
        /// <param name="vertexIdSet"></param>
        /// <param name="vertexPartitionKeySet"></param>
        public static void ConstructLazyAdjacencyList(
            GraphViewCommand command,
            EdgeType edgeType,
            HashSet <string> vertexIdSet,
            HashSet <string> vertexPartitionKeySet)
        {
            if (!vertexIdSet.Any())
            {
                return;
            }

            const string ALIAS = "edgeDoc";

            var queryBoth = new JsonQuery
            {
                EdgeAlias = ALIAS
            };

            queryBoth.AddSelectElement("*");
            queryBoth.RawWhereClause = new WInPredicate(new WColumnReferenceExpression(ALIAS, KW_EDGEDOC_VERTEXID), vertexIdSet.ToList());
            queryBoth.FlatProperties.Add(KW_EDGEDOC_VERTEXID);

            if (vertexPartitionKeySet.Any())
            {
                // TODO: Refactor this.
                queryBoth.WhereConjunction(new WInPredicate(new WValueExpression($"{ALIAS}{command.Connection.GetPartitionPathIndexer()}"), vertexPartitionKeySet.ToList()),
                                           BooleanBinaryExpressionType.And);
            }
            if (edgeType == EdgeType.Outgoing)
            {
                queryBoth.WhereConjunction(new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    FirstExpr      = new WColumnReferenceExpression(ALIAS, KW_EDGEDOC_ISREVERSE),
                    SecondExpr     = new WValueExpression("false")
                }, BooleanBinaryExpressionType.And);
                queryBoth.FlatProperties.Add(KW_EDGEDOC_ISREVERSE);
            }
            else if (edgeType == EdgeType.Incoming)
            {
                queryBoth.WhereConjunction(new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    FirstExpr      = new WColumnReferenceExpression(ALIAS, KW_EDGEDOC_ISREVERSE),
                    SecondExpr     = new WValueExpression("true")
                }, BooleanBinaryExpressionType.And);
                queryBoth.FlatProperties.Add(KW_EDGEDOC_ISREVERSE);
            }

//            var qqq = queryBoth.ToJsonServerString();

            List <JObject> edgeDocuments = command.Connection.CreateDatabasePortal().GetEdgeDocuments(queryBoth);

            // Dictionary<vertexId, Dictionary<edgeDocumentId, edgeDocument>>
            var edgeDict = new Dictionary <string, Dictionary <string, JObject> >();

            foreach (JObject edgeDocument in edgeDocuments)
            {
                // Save edgeDocument's etag if necessary
                command.VertexCache.SaveCurrentEtagNoOverride(edgeDocument);
            }

            EdgeDocumentHelper.FillEdgeDict(edgeDict, edgeDocuments);

            //
            // Use all edges whose sink is vertexId to construct a virtual reverse adjacency list of this vertex
            //
            if (!command.Connection.UseReverseEdges && edgeType.HasFlag(EdgeType.Incoming))
            {
                // TODO: old Version JsonQuery, delete it when you understand this query.
//                string selectClause = $"{{" +
//                               $"  \"{EdgeDocumentHelper.VirtualReverseEdgeObject}\": edge, " +
//                               $"  \"{KW_EDGE_SRCV}\": doc.{KW_DOC_ID}, " +
//                               $"  \"{KW_EDGE_SRCV_LABEL}\": doc.{KW_VERTEX_LABEL}," +
//                               (command.Connection.PartitionPath != null
//                                   ? $"  \"{KW_EDGE_SRCV_PARTITION}\": doc{command.Connection.GetPartitionPathIndexer()},"
//                                   : "") +
//                               $"  \"{KW_EDGEDOC_VERTEXID}\": doc.{KW_EDGEDOC_VERTEXID}," +
//                               $"  \"{KW_EDGEDOC_VERTEX_LABEL}\": doc.{KW_EDGEDOC_VERTEX_LABEL}" +
//                               $"}} AS {EdgeDocumentHelper.VirtualReverseEdge}";
//                string alise = "doc";
//                string joinClause = $"JOIN edge IN doc.{DocumentDBKeywords.KW_VERTEX_EDGE}";
//                string inClause = string.Join(", ", vertexIdSet.Select(vertexId => $"'{vertexId}'"));
//                string whereSearchCondition = $"edge.{KW_EDGE_SINKV} IN ({inClause})";

                const string NODE_ALISE_S  = "node";
                const string EDGE_ALISE_S  = "edge";
                var          queryReversed = new JsonQuery
                {
                    NodeAlias = NODE_ALISE_S,
                    EdgeAlias = EDGE_ALISE_S
                };
                // Construct select clause.
                List <WPrimaryExpression> selectList = new List <WPrimaryExpression>
                {
                    new WValueExpression($"{{  \"{EdgeDocumentHelper.VirtualReverseEdgeObject}\": "),
                    new WColumnReferenceExpression(EDGE_ALISE_S, "*"),
                    new WValueExpression($",  \"{KW_EDGE_SRCV}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_DOC_ID),
                    new WValueExpression($",  \"{KW_EDGE_SRCV_LABEL}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_VERTEX_LABEL),
                    new WValueExpression($",  \"{KW_EDGEDOC_VERTEXID}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_EDGEDOC_VERTEXID),
                    new WValueExpression($",  \"{KW_EDGEDOC_VERTEX_LABEL}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_EDGEDOC_VERTEX_LABEL),
                };
                if (command.Connection.PartitionPath != null)
                {
                    selectList.Add(new WValueExpression($",  \"{KW_EDGE_SRCV_PARTITION}\": "));
                    // TODO: hack operation, when meet columnName[0] = '[', the toDocDbString function will do something special.
                    selectList.Add(new WColumnReferenceExpression(NODE_ALISE_S, command.Connection.GetPartitionPathIndexer()));
                }
                selectList.Add(new WValueExpression("}"));
                queryReversed.AddSelectElement(EdgeDocumentHelper.VirtualReverseEdge, selectList);

                // Construct join clause
                queryReversed.JoinDictionary.Add(EDGE_ALISE_S, $"{NODE_ALISE_S}.{DocumentDBKeywords.KW_VERTEX_EDGE}");

                // construct where clause
                queryReversed.RawWhereClause = new WInPredicate(
                    new WColumnReferenceExpression(EDGE_ALISE_S, KW_EDGE_SINKV),
                    new List <string>(vertexIdSet));


                edgeDocuments = command.Connection.CreateDatabasePortal().GetEdgeDocuments(queryReversed);

                List <JObject> virtualReverseEdgeDocuments = EdgeDocumentHelper.ConstructVirtualReverseEdgeDocuments(edgeDocuments);

                EdgeDocumentHelper.FillEdgeDict(edgeDict, virtualReverseEdgeDocuments);
            }

            foreach (KeyValuePair <string, Dictionary <string, JObject> > pair in edgeDict)
            {
                string vertexId = pair.Key;
                Dictionary <string, JObject> edgeDocDict = pair.Value; // contains both in & out edges
                VertexField vertexField;
                command.VertexCache.TryGetVertexField(vertexId, out vertexField);
                vertexField.ConstructSpilledOrVirtualAdjacencyListField(edgeType, edgeDocDict);
                vertexIdSet.Remove(vertexId);
            }

            foreach (string vertexId in vertexIdSet)
            {
                VertexField vertexField;
                command.VertexCache.TryGetVertexField(vertexId, out vertexField);
                vertexField.ConstructSpilledOrVirtualAdjacencyListField(edgeType, new Dictionary <string, JObject>());
            }
        }
예제 #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="vertexObject"></param>
        /// <param name="edgeDocId"></param>
        /// <param name="isReverse"></param>
        /// <param name="newEdgeObject"></param>
        public static void UpdateEdgeProperty(
            GraphViewCommand command,
            JObject vertexObject,
            string edgeDocId,     // Can be null
            bool isReverse,
            JObject newEdgeObject // With all metadata (including id, partition, srcV/sinkV, edgeId)
            )
        {
            bool   tooLarge;
            string srcOrSinkVInEdgeObject = isReverse ? KW_EDGE_SRCV : KW_EDGE_SINKV;

            if (edgeDocId == null)
            {
                JArray edgeContainer = (JArray)vertexObject[isReverse ? KW_VERTEX_REV_EDGE : KW_VERTEX_EDGE];

                // Don't use JToken.Replace() here.
                // Make sure the currently modified edge is the last child of edgeContainer, which
                // garantees the newly created edge-document won't be too large.
                //
                // NOTE: The following line applies for both incomming and outgoing edge.
                edgeContainer.Children <JObject>().First(
                    e => (string)e[KW_EDGE_ID] == (string)newEdgeObject[KW_EDGE_ID] &&
                    (string)e[srcOrSinkVInEdgeObject] == (string)newEdgeObject[srcOrSinkVInEdgeObject]
                    ).Remove();
                edgeContainer.Add(newEdgeObject);

                UploadOne(command, (string)vertexObject[KW_DOC_ID], vertexObject, false, out tooLarge);
                if (tooLarge)
                {
                    // Handle this situation: The updated edge is too large to be filled into the vertex-document
                    string existEdgeDocId, newEdgeDocId;
                    bool?  spillReverse = null;
                    EdgeDocumentHelper.SpillVertexEdgesToDocument(command, vertexObject, ref spillReverse, out existEdgeDocId, out newEdgeDocId);
                }
            }
            else
            {
                // Large vertex

                JObject edgeDocObject = command.Connection.RetrieveDocumentById(edgeDocId, command.Connection.GetDocumentPartition(vertexObject), command);
                edgeDocObject[KW_EDGEDOC_EDGE].Children <JObject>().First(
                    e => (string)e[KW_EDGE_ID] == (string)newEdgeObject[KW_EDGE_ID] &&
                    (string)e[srcOrSinkVInEdgeObject] == (string)newEdgeObject[srcOrSinkVInEdgeObject]
                    ).Remove();
                ((JArray)edgeDocObject[KW_EDGEDOC_EDGE]).Add(newEdgeObject);
                UploadOne(command, edgeDocId, edgeDocObject, false, out tooLarge);
                if (tooLarge)
                {
                    if (command.Connection.EdgeSpillThreshold == 1)
                    {
                        throw new GraphViewException("The edge is too large to be stored in one document!");
                    }

                    // Handle this situation: The modified edge is too large to be filled into the original edge-document
                    // Remove the edgeObject added just now, and upload the original edge-document
                    ((JArray)edgeDocObject[KW_EDGEDOC_EDGE]).Last.Remove();
                    UploadOne(command, edgeDocId, edgeDocObject, false, out tooLarge);
                    Debug.Assert(!tooLarge);

                    // Insert the edgeObject to one of the vertex's edge-documents
                    InsertEdgeObjectInternal(command, vertexObject, null, newEdgeObject, isReverse, out edgeDocId);
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Insert edgeObject to one a vertex.
        /// NOTE: vertex-document and edge-document(s) are uploaded.
        /// NOTE: If changing _edge/_reverse_edge field from JArray to JObject, the "EdgeDocId" of existing
        ///       edges in VertexCache are updated (from null to the newly created edge-document's id)
        /// NOTE: Adding the newly created edge into VertexCache is not operated by this function. Actually,
        ///       if called by <see cref="UpdateEdgeProperty"/>, VertexCache should be updated by setting an
        ///       edge's property, but not adding a new edge.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="vertexObject"></param>
        /// <param name="vertexField">Can be null if we already know edgeContainer is JObject</param>
        /// <param name="edgeObject"></param>
        /// <param name="isReverse"></param>
        /// <param name="newEdgeDocId"></param>
        internal static void InsertEdgeObjectInternal(
            GraphViewCommand command,
            JObject vertexObject,
            VertexField vertexField,
            JObject edgeObject,
            bool isReverse,
            out string newEdgeDocId)
        {
            bool   tooLarge;
            JArray edgeContainer = (JArray)vertexObject[isReverse ? KW_VERTEX_REV_EDGE : KW_VERTEX_EDGE]; // JArray or JObject
            bool   isSpilled     = IsSpilledVertex(vertexObject, isReverse);

            //
            // This graph is compatible only, thus add an edge-document directly
            //
            if (command.Connection.GraphType != GraphType.GraphAPIOnly || command.Connection.EdgeSpillThreshold == 1)
            {
                Debug.Assert(command.Connection.EdgeSpillThreshold == 1);

                // Create a new edge-document to store the edge.
                JObject edgeDocObject = new JObject {
                    [KW_DOC_ID]               = GraphViewConnection.GenerateDocumentId(),
                    [KW_EDGEDOC_ISREVERSE]    = isReverse,
                    [KW_EDGEDOC_VERTEXID]     = (string)vertexObject[KW_DOC_ID],
                    [KW_EDGEDOC_VERTEX_LABEL] = (string)vertexObject[KW_VERTEX_LABEL],
                    [KW_EDGEDOC_EDGE]         = new JArray(edgeObject),
                    [KW_EDGEDOC_IDENTIFIER]   = (JValue)true,
                };
                if (command.Connection.PartitionPathTopLevel != null)
                {
                    // This may be KW_DOC_PARTITION, maybe not
                    edgeDocObject[command.Connection.PartitionPathTopLevel] = vertexObject[command.Connection.PartitionPathTopLevel];
                }

                // Upload the edge-document
                bool dummyTooLarge;
                UploadOne(command, (string)edgeDocObject[KW_DOC_ID], edgeDocObject, true, out dummyTooLarge);
                Debug.Assert(!dummyTooLarge);


                newEdgeDocId = (string)edgeDocObject[KW_DOC_ID];
                return;
            }


            if (isSpilled)
            {
                // Now it is a large-degree vertex, and contains at least 1 edge-document
                JArray edgeDocumentsArray = edgeContainer;
                Debug.Assert(edgeDocumentsArray != null, "edgeDocumentsArray != null");
                Debug.Assert(edgeDocumentsArray.Count == 1, "edgeDocumentsArray.Count == 1");

                string  lastEdgeDocId = (string)edgeDocumentsArray.Last[KW_DOC_ID];
                JObject edgeDocument  = command.Connection.RetrieveDocumentById(lastEdgeDocId, vertexField.Partition, command);
                Debug.Assert(((string)edgeDocument[KW_DOC_ID]).Equals(lastEdgeDocId), $"((string)edgeDocument[{KW_DOC_ID}]).Equals(lastEdgeDocId)");
                Debug.Assert((bool)edgeDocument[KW_EDGEDOC_ISREVERSE] == isReverse, $"(bool)edgeDocument['{KW_EDGEDOC_ISREVERSE}'] == isReverse");
                Debug.Assert((string)edgeDocument[KW_EDGEDOC_VERTEXID] == (string)vertexObject[KW_DOC_ID], $"(string)edgeDocument['{KW_EDGEDOC_VERTEXID}'] == (string)vertexObject['{KW_DOC_ID}']");

                JArray edgesArray = (JArray)edgeDocument[KW_EDGEDOC_EDGE];
                Debug.Assert(edgesArray != null, "edgesArray != null");
                Debug.Assert(edgesArray.Count > 0, "edgesArray.Count > 0");

                if (command.Connection.EdgeSpillThreshold == 0)
                {
                    // Don't spill an edge-document until it is too large
                    edgesArray.Add(edgeObject);
                    tooLarge = false;
                }
                else
                {
                    // Explicitly specified a threshold
                    Debug.Assert(command.Connection.EdgeSpillThreshold > 0, "connection.EdgeSpillThreshold > 0");
                    if (edgesArray.Count >= command.Connection.EdgeSpillThreshold)
                    {
                        // The threshold is reached!
                        tooLarge = true;
                    }
                    else
                    {
                        // The threshold is not reached
                        edgesArray.Add(edgeObject);
                        tooLarge = false;
                    }
                }

                // If the edge-document is not too large (reach the threshold), try to
                //   upload the edge into the document
                if (!tooLarge)
                {
                    UploadOne(command, lastEdgeDocId, edgeDocument, false, out tooLarge);
                }
                if (tooLarge)
                {
                    // The edge is too large to be filled into the last edge-document
                    // or the threashold is reached:
                    // Create a new edge-document to store the edge.
                    JObject edgeDocObject = new JObject {
                        [KW_DOC_ID]               = GraphViewConnection.GenerateDocumentId(),
                        [KW_EDGEDOC_ISREVERSE]    = isReverse,
                        [KW_EDGEDOC_VERTEXID]     = (string)vertexObject[KW_DOC_ID],
                        [KW_EDGEDOC_VERTEX_LABEL] = (string)vertexObject[KW_VERTEX_LABEL],
                        [KW_EDGEDOC_EDGE]         = new JArray(edgeObject),
                        [KW_EDGEDOC_IDENTIFIER]   = (JValue)true,
                    };
                    if (command.Connection.PartitionPathTopLevel != null)
                    {
                        // This may be KW_DOC_PARTITION, maybe not
                        edgeDocObject[command.Connection.PartitionPathTopLevel] = vertexObject[command.Connection.PartitionPathTopLevel];
                    }
                    lastEdgeDocId = command.Connection.CreateDocumentAsync(edgeDocObject, command).Result;

                    // Replace the newly created edge-document to vertexObject
                    Debug.Assert(edgeDocumentsArray.Count == 1);
                    edgeDocumentsArray[0][KW_DOC_ID] = lastEdgeDocId;
                }
                newEdgeDocId = lastEdgeDocId;

                // Upload the vertex documention (at least, its _nextXxx is changed)
                bool dummyTooLarge;
                UploadOne(command, (string)vertexObject[KW_DOC_ID], vertexObject, false, out dummyTooLarge);
                Debug.Assert(!dummyTooLarge);
            }
            else
            {
                // This vertex is not spilled
                bool?spillReverse;
                ((JArray)edgeContainer).Add(edgeObject);
                if (command.Connection.EdgeSpillThreshold == 0)
                {
                    // Don't spill an edge-document until it is too large
                    tooLarge     = false;
                    spillReverse = null;
                }
                else
                {
                    // Explicitly specified a threshold
                    Debug.Assert(command.Connection.EdgeSpillThreshold > 0, "connection.EdgeSpillThreshold > 0");
                    tooLarge     = (((JArray)edgeContainer).Count > command.Connection.EdgeSpillThreshold);
                    spillReverse = isReverse;
                }

                if (!tooLarge)
                {
                    UploadOne(command, (string)vertexObject[KW_DOC_ID], vertexObject, false, out tooLarge);
                }
                if (tooLarge)
                {
                    string existEdgeDocId;
                    // The vertex object is uploaded in SpillVertexEdgesToDocument
                    EdgeDocumentHelper.SpillVertexEdgesToDocument(command, vertexObject, ref spillReverse, out existEdgeDocId, out newEdgeDocId);

                    // the edges are spilled into two ducuments.
                    // one stores old edges(docId = existEdgeDocId), the other one stores the new edge.
                    // Because the new edge is not in the vertexCache, hence we can set all edges' docId as existEdgeDocId
                    Debug.Assert(spillReverse != null);
                    Debug.Assert(vertexField != null);
                    if (spillReverse.Value)
                    {
                        vertexField.RevAdjacencyList.ResetFetchedEdgesDocId(existEdgeDocId);
                    }
                    else
                    {
                        vertexField.AdjacencyList.ResetFetchedEdgesDocId(existEdgeDocId);
                    }
                }
                else
                {
                    newEdgeDocId = null;
                }
            }
        }
예제 #10
0
        /// <summary>
        /// For every vertex in the vertexIdSet, retrieve their spilled edge documents to construct their forward or backward
        /// adjacency list.
        /// When connection.useReverseEdge is false, this method will retrieve all the forward edge documents whose sink
        /// is the target vertex to build a virtual reverse adjacency list.
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="vertexIdSet"></param>
        public static void ConstructSpilledAdjListsOrVirtualRevAdjListsOfVertices(GraphViewConnection connection,
                                                                                  HashSet <string> vertexIdSet)
        {
            if (!vertexIdSet.Any())
            {
                return;
            }

            string inClause           = string.Join(", ", vertexIdSet.Select(vertexId => $"'{vertexId}'"));
            string edgeDocumentsQuery =
                $"SELECT * " +
                $"FROM edgeDoc " +
                $"WHERE edgeDoc.{KW_EDGEDOC_VERTEXID} IN ({inClause})";
            List <dynamic> edgeDocuments = connection.ExecuteQuery(edgeDocumentsQuery).ToList();

            // Dictionary<vertexId, Dictionary<edgeDocumentId, edgeDocument>>
            Dictionary <string, Dictionary <string, JObject> > edgeDict =
                new Dictionary <string, Dictionary <string, JObject> >();

            foreach (JObject edgeDocument in edgeDocuments)
            {
                // Save edgeDocument's etag if necessary
                connection.VertexCache.SaveCurrentEtagNoOverride(edgeDocument);
            }

            EdgeDocumentHelper.FillEdgeDict(edgeDict, edgeDocuments);

            //
            // Use all edges whose sink is vertexId to construct a virtual reverse adjacency list of this vertex
            //
            if (!connection.UseReverseEdges)
            {
                edgeDocumentsQuery =
                    $"SELECT {{" +
                    $"  \"{EdgeDocumentHelper.VirtualReverseEdgeObject}\": edge, " +
                    $"  \"{KW_EDGE_SRCV}\": doc.{KW_DOC_ID}, " +
                    $"  \"{KW_EDGE_SRCV_LABEL}\": doc.{KW_EDGE_SRCV_LABEL}," +
                    $"  \"{KW_EDGEDOC_VERTEXID}\": doc.{KW_EDGEDOC_VERTEXID}" +
                    $"}} AS {EdgeDocumentHelper.VirtualReverseEdge}\n" +
                    $"FROM doc\n" +
                    $"JOIN edge IN doc.{GraphViewKeywords.KW_VERTEX_EDGE}\n" +
                    $"WHERE edge.{KW_EDGE_SINKV} IN ({inClause})";

                edgeDocuments = connection.ExecuteQuery(edgeDocumentsQuery).ToList();

                Dictionary <string, string> labelOfSrcVertexOfSpilledEdges =
                    EdgeDocumentHelper.GetLabelOfSrcVertexOfSpilledEdges(connection, edgeDocuments);

                List <JObject> virtualReverseEdgeDocuments =
                    EdgeDocumentHelper.ConstructVirtualReverseEdgeDocuments(edgeDocuments, labelOfSrcVertexOfSpilledEdges);

                EdgeDocumentHelper.FillEdgeDict(edgeDict, virtualReverseEdgeDocuments.Cast <dynamic>().ToList());
            }

            foreach (KeyValuePair <string, Dictionary <string, JObject> > pair in edgeDict)
            {
                string vertexId = pair.Key;
                Dictionary <string, JObject> edgeDocDict = pair.Value; // contains both in & out edges
                VertexField vertexField;
                connection.VertexCache.TryGetVertexField(vertexId, out vertexField);
                vertexField.ConstructSpilledOrVirtualAdjacencyListField(edgeDocDict);
                vertexIdSet.Remove(vertexId);
            }

            foreach (string vertexId in vertexIdSet)
            {
                VertexField vertexField;
                connection.VertexCache.TryGetVertexField(vertexId, out vertexField);
                vertexField.ConstructSpilledOrVirtualAdjacencyListField(new Dictionary <string, JObject>());
            }
        }