internal static void AssertGraphsEqual(PropertyGraphModel expected, PropertyGraphModel actual) { var left = (JObject)JsonConvert.DeserializeObject(JsonConvention.SerializeObject(SortGraph(expected))); var right = (JObject)JsonConvert.DeserializeObject(JsonConvention.SerializeObject(SortGraph(actual))); Sort(left); Sort(right); Assert.AreEqual(left.ToString(Formatting.None), right.ToString(Formatting.None)); //Assert.AreEqual(JsonConvention.SerializeObject(SortGraph(expected)), JsonConvention.SerializeObject(SortGraph(actual))); }
public async override Task Execute(SaveVertexCommand cmd) { var vertexProps = await UnitOfWork.Db.VertexProperties.Where( p => p.VertexId == cmd.VertexId && p.Deleted == null).ToListAsync(); foreach (var propModel in cmd.Props) { // close old value if present var prop = vertexProps.FirstOrDefault(p => p.SchemaUri == propModel.SchemaUri); // serialize value to json var jsonValue = JsonConvention.SerializeObject(propModel.Value); if (prop != null) { if (prop.JsonValue == jsonValue) { // nothing to update continue; } else { // different value - close old property and continue prop.Deleted = _clock.TimeStamp; } } // if value is null do not add anything if (propModel.Value == null) { continue; } // create property var newProp = new VertexProperty() { Id = Guid.NewGuid(), VertexId = cmd.VertexId, SchemaUri = propModel.SchemaUri, Created = _clock.TimeStamp, JsonValue = jsonValue }; UnitOfWork.Db.VertexProperties.Add(newProp); // prevent inserting duplicates vertexProps.Add(newProp); } await Events.OnNext(new SaveVertexCompletedEvent() { Command = cmd }); }
public static HashSet <object> AsSet(this object value) { var str = value.ToString(); if (str.StartsWith("[") && str.EndsWith("]")) { return(JsonConvention.DeserializeObject <HashSet <object> >(str)); } return(new HashSet <object>() { value }); }
/// <summary> /// Assumes layout has been already applied /// Note: method mutates graph and graphLayout /// </summary> public void ImproveAppliedLayout(SigmaGraphModel graph, GraphLayout graphLayout, LayoutSettings layoutSettings, TimeSpan duration) { using (var engine = new V8ScriptEngine()) { try { var v8Graph = new V8GraphModel(); v8Graph.LoadSigma(graph); engine.AddHostObject("log", _log); engine.Execute("var graph = " + JsonConvention.SerializeObject(v8Graph) + ";"); engine.Execute("var settings = " + JsonConvention.SerializeObject(layoutSettings) + ";"); engine.Execute("var duration = " + JsonConvention.SerializeObject(duration.TotalMilliseconds) + ";"); var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; var forceAtlas2 = engine.Compile(File.ReadAllText($@"{baseDirectory}\App\Graph\Layout\ForceAtlas2.js")); var serviceScript = engine.Compile(File.ReadAllText($@"{baseDirectory}\App\Graph\Layout\GraphLayoutService.js")); engine.Execute(forceAtlas2); engine.Execute(serviceScript); var nodesJson = engine.Evaluate("JSON.stringify(nodes)").ToString(); var nodes = JsonConvention.DeserializeObject <V8NodeModel[]>(nodesJson); for (int i = 0; i < nodes.Length; i++) { var node = graph.Nodes[i]; node.X = nodes[i].x; node.Y = nodes[i].y; var id = node.Entity; if (id.HasValue) { graphLayout[id.Value] = new GraphLayout.Coords() { X = nodes[i].x, Y = nodes[i].y }; } } } catch (ScriptEngineException e) { _log.Error("V8 exception: " + e.ErrorDetails); throw; } } }
public async override Task Execute(CreateVertexCommand cmd) { UnitOfWork.Db.Vertices.Add(new Vertex() { Id = cmd.VertexId, NetworkId = cmd.NetworkId, Created = _clock.TimeStamp }); if (cmd.Props != null) { foreach (var propModel in cmd.Props) { // serialize value to json var jsonValue = JsonConvention.SerializeObject(propModel.Value); // if value is null do not add anything if (propModel.Value == null) { continue; } // create property var newProp = new VertexProperty() { Id = Guid.NewGuid(), VertexId = cmd.VertexId, SchemaUri = propModel.SchemaUri, Created = _clock.TimeStamp, JsonValue = jsonValue }; UnitOfWork.Db.VertexProperties.Add(newProp); } } await Events.OnNext(new SaveVertexCompletedEvent() { Command = new SaveVertexCommand() { VertexId = cmd.VertexId, Props = cmd.Props } }); }
internal static void AssertGraphsEqual(string expected, string actual) { AssertGraphsEqual(JsonConvention.DeserializeObject <PropertyGraphModel>(expected), JsonConvention.DeserializeObject <PropertyGraphModel>(actual)); }
public async override Task Execute(SaveEdgeCommand cmd) { // is the relationship already there? var edge = await UnitOfWork.Db.Edges.Where( e => e.SourceVertexId == cmd.SourceVertexId && e.TargetVertexId == cmd.TargetVertexId && e.SchemaUri == cmd.SchemaUri && e.Deleted == null).FirstOrDefaultAsync(); var edgeExists = (edge != null); if (!edgeExists) { // relationship not found - create edge edge = new Entities.Edge() { Id = Guid.NewGuid(), SourceVertexId = cmd.SourceVertexId, TargetVertexId = cmd.TargetVertexId, SchemaUri = cmd.SchemaUri, Created = _clock.TimeStamp, }; UnitOfWork.Db.Edges.Add(edge); } if (cmd.Props != null) { var edgeProps = await UnitOfWork.Db.EdgeProperties.Where( p => p.EdgeId == edge.Id && p.Deleted == null) .ToListAsync(); foreach (var propModel in cmd.Props) { var jsonValue = JsonConvention.SerializeObject(propModel.Value); if (edgeExists) { // relationship found - find if the proeprty isn't already there var prop = edgeProps.SingleOrDefault(p => p.SchemaUri == propModel.SchemaUri); if (prop != null) { if (prop.JsonValue == jsonValue) { // nothing to update continue; } else { // different value - close old property and continue prop.Deleted = _clock.TimeStamp; } } } // if value is null do not add anything if (propModel.Value == null) { continue; } // create property var newProp = new EdgeProperty() { Id = Guid.NewGuid(), EdgeId = edge.Id, SchemaUri = propModel.SchemaUri, Created = _clock.TimeStamp, JsonValue = jsonValue }; UnitOfWork.Db.EdgeProperties.Add(newProp); // prevent inserting duplicate props edgeProps.Add(newProp); } } await Events.OnNext(new SaveEdgeCompletedEvent() { Command = cmd }); }
public override async Task <List <DuplicateResult> > Execute(DuplicatesQuery query) { var graph = (await _queryService.Execute(new InternalGraphQuery() { NetworkId = query.NetworkId }, this)) .Snapshot(); var settings = await _queryService.Execute(new NetworkSettingsQuery() { NetworkId = query.NetworkId }, this); var requiredProps = settings.Invitations.RequiredProps; var duplicatesByRequiredProps = graph.Vertices.Select( v => new { Key = string.Join("::", requiredProps.Select(prop => v.Props.ContainsKey(prop) ? JsonConvention.SerializeObject(v.Props[prop]) : "")), Vertex = v }) .GroupBy(g => g.Key) .Where(g => g.Count(v => true) > 1) .Select(g => new Duplicate() { Score = 1, Key = g.Select(a => a.Vertex.Id).OrderBy(id => id).ToArray(), Vertices = g.Select(a => a.Vertex) }); var labelProp = settings.ProfileCard.LabelProp; var duplicatesByLabel = graph.Vertices.Select( v => new { Label = v.Props.ContainsKey(labelProp) ? v.Props[labelProp].ToString().ToLowerInvariant().Trim() : "", Vertex = v }) .GroupBy(g => g.Label) .Where(g => g.Count(v => true) > 1) .Select(g => new Duplicate() { Score = 0.5, Key = g.Select(a => a.Vertex.Id).OrderBy(id => id).ToArray(), Vertices = g.Select(a => a.Vertex) }); var duplicates = duplicatesByRequiredProps.ToDictionary(d => d.Key, d => d, new ArrayEqualityComparer()); foreach (var duplicate in duplicatesByLabel) { if (!duplicates.ContainsKey(duplicate.Key)) { duplicates[duplicate.Key] = duplicate; } } var accounts = await (from account in _repo.Db.Accounts join user in _repo.Db.Users on account.ApplicationUserId equals user.Id join vertex in _repo.Db.Vertices on account.VertexId equals vertex.Id where vertex.NetworkId == query.NetworkId group new { user.Email, account.InvitationDate } by vertex.Id into g select new { VertexId = g.Key, Accounts = g.ToList() } ).ToDictionaryAsync(g => g.VertexId, g => g.Accounts.OrderBy(a => a.InvitationDate)); var result = new List <DuplicateResult>(); foreach (var duplicate in duplicates.Values.OrderByDescending(d => d.Score)) { foreach (var vertex in duplicate.Vertices) { vertex.Props = vertex.Props.ToProfileCardProps(settings.ProfileCard); if (accounts.ContainsKey(vertex.Id)) { vertex.Props["Account email"] = accounts[vertex.Id].First().Email; } } var firstAccountVertex = duplicate.Vertices.Select(v => new { Vertex = v, InvitationDate = accounts.ContainsKey(v.Id) ? accounts[v.Id].First().InvitationDate : DateTime.MaxValue }).OrderBy(a => a.InvitationDate).First(); result.Add(new DuplicateResult() { Vertex = firstAccountVertex.Vertex, Duplicates = duplicate.Vertices.Where(v => v != firstAccountVertex.Vertex).ToList() }); } return(result); }
public Dictionary <Tuple <Guid, Guid, string>, ConcurrentEdgeModel> GenerateConcurrentEdgeModel(GraphSchemaModel schema, InternalGraphEdgesResult edges) { // var uriNameDictionary = schema.EdgeSchema.ToDictionary(e => e.Uri, e => e.Name); // source, target, edgeName, propName => timestamp var propTimestamps = new Dictionary <Tuple <Guid, Guid, string, string>, DateTime>(); // edges var edgesResult = new Dictionary <Tuple <Guid, Guid, string>, ConcurrentEdgeModel>(); foreach (var relationshipSchema in schema.EdgeSchema) { // możliwe jest wiele relacji do różnych węzłów (a każda może mieć wiele propsów) Dictionary <Tuple <Guid, Guid>, InternalGraphEdgesResult.InternalEdgeModel> edgeBucket; if (!edges.Edges.TryGetValue(relationshipSchema.Uri, out edgeBucket)) { continue; } foreach (var edge in edgeBucket) { var edgeKey = new Tuple <Guid, Guid, string>(edge.Key.Item1, edge.Key.Item2, uriNameDictionary[relationshipSchema.Uri]); // find model ConcurrentEdgeModel edgeModel; if (!edgesResult.TryGetValue(edgeKey, out edgeModel)) { edgeModel = new ConcurrentEdgeModel() { Id = edge.Value.Id, SourceVertexId = edge.Value.SourceId, TargetVertexId = edge.Value.TargetId, Name = relationshipSchema.Name, Props = new ConcurrentDictionary <string, object>(StringComparer.OrdinalIgnoreCase) }; edgesResult.Add(edgeKey, edgeModel); } if (relationshipSchema.PropsSchema != null) { foreach (var propSchema in relationshipSchema.PropsSchema) { if (!edge.Value.PropsJson.ContainsKey(propSchema.Uri)) { continue; } if (edgeModel.Props.ContainsKey(propSchema.Name)) { continue; } var prop = edge.Value.PropsJson[propSchema.Uri]; if (!edgeModel.Props.ContainsKey(propSchema.Name)) { var value = JsonConvention.DeserializeObject(prop.JsonValue); edgeModel.Props.TryAdd(propSchema.Name, value); } else { // check timestamp for update (newer props override older) var timestampKey = new Tuple <Guid, Guid, string, string>(edgeModel.SourceVertexId, edgeModel.TargetVertexId, edgeModel.Name, propSchema.Name); var timestamp = propTimestamps[timestampKey]; if (timestamp < prop.TimeStamp) { var value = JsonConvention.DeserializeObject(prop.JsonValue); edgeModel.Props.TryAdd(propSchema.Name, value); } } } } } } return(edgesResult); }
public Dictionary <Guid, ConcurrentVertexModel> GenerateConcurrentVertexModel(GraphSchemaModel schema, InternalGraphVerticesResult vertices) { var vertexIdPropNameTimeStamp = new Dictionary <Tuple <Guid, String>, DateTime>(new TupeGuidStringComparer()); var verticesResult = new Dictionary <Guid, ConcurrentVertexModel>(); var processedPropUris = new HashSet <string>(); foreach (var sectionSchema in schema.VertexSchema) { if (sectionSchema.PropsSchema != null) { foreach (var propSchema in sectionSchema.PropsSchema) { List <InternalGraphVerticesResult.InternalVertexPropModel> propsBucket; if (!vertices.WithProps.TryGetValue(propSchema.Uri, out propsBucket)) { continue; } processedPropUris.Add(propSchema.Uri); foreach (var prop in propsBucket) { ConcurrentVertexModel vertex; if (!verticesResult.TryGetValue(prop.VertexId, out vertex)) { vertex = new ConcurrentVertexModel() { Id = prop.VertexId, Props = new ConcurrentDictionary <string, object>(StringComparer.OrdinalIgnoreCase) }; verticesResult.Add(prop.VertexId, vertex); } if (!vertex.Props.ContainsKey(propSchema.Name)) { var value = JsonConvention.DeserializeObject(prop.JsonValue); vertex.Props.TryAdd(propSchema.Name, value); vertexIdPropNameTimeStamp.Add(new Tuple <Guid, string>(vertex.Id, propSchema.Name), prop.TimeStamp); } else { // should we override the value? DateTime lastTimeStamp = vertexIdPropNameTimeStamp[new Tuple <Guid, string>(vertex.Id, propSchema.Name)]; if (lastTimeStamp < prop.TimeStamp) { var value = JsonConvention.DeserializeObject(prop.JsonValue); vertex.Props[propSchema.Name] = value; } } } } } } // handle props outside schema var outsideSchema = vertices.WithProps.Where(v => !processedPropUris.Contains(v.Key)); foreach (var propsBucket in outsideSchema) { var name = propsBucket.Key.Split('/').Last(); foreach (var prop in propsBucket.Value) { ConcurrentVertexModel vertex; if (!verticesResult.TryGetValue(prop.VertexId, out vertex)) { vertex = new ConcurrentVertexModel() { Id = prop.VertexId, Props = new ConcurrentDictionary <string, object>(StringComparer.OrdinalIgnoreCase) }; verticesResult.Add(prop.VertexId, vertex); } if (!vertex.Props.ContainsKey(name)) { var value = JsonConvention.DeserializeObject(prop.JsonValue); vertex.Props.TryAdd(name, value); vertexIdPropNameTimeStamp.Add(new Tuple <Guid, string>(vertex.Id, name), prop.TimeStamp); } else { // should we override the value? DateTime lastTimeStamp = vertexIdPropNameTimeStamp[new Tuple <Guid, string>(vertex.Id, name)]; if (lastTimeStamp < prop.TimeStamp) { var value = JsonConvention.DeserializeObject(prop.JsonValue); vertex.Props[name] = value; } } } } // vertices witour props foreach (var withoutProp in vertices.WithoutProps) { verticesResult.Add(withoutProp, new ConcurrentVertexModel() { Id = withoutProp, Props = new ConcurrentDictionary <string, object>(StringComparer.OrdinalIgnoreCase) }); } return(verticesResult); }