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 }); }
/// <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 } }); }
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); }