

public class KnowledgeGraphFilteredFindPathsResults
Public Class KnowledgeGraphFilteredFindPathsResults
//using ArcGIS.Core.Data.Knowledge.Extensions;
await QueuedTask.Run(() =>
{
var ffp_config = new CIMFilteredFindPathsConfiguration();
ffp_config.Name = "Run FFP Using Defaults";
//Origin Entities
var originEntities = new List<CIMFilteredFindPathsEntity>();
var poi_entity = new CIMFilteredFindPathsEntity();
poi_entity.EntityTypeName = "POI";//All entities of entity type "POI"
poi_entity.PropertyFilterPredicate = "";
originEntities.Add(poi_entity);
//Add the CIMFilteredFindPathsEntity to the OriginEntities collection
ffp_config.OriginEntities = originEntities.ToArray();
//Destination Entities
var destEntities = new List<CIMFilteredFindPathsEntity>();
var supp_entity = new CIMFilteredFindPathsEntity();
supp_entity.EntityTypeName = "Supplier";//All entities of entity type "Supplier"
supp_entity.PropertyFilterPredicate = "";
destEntities.Add(supp_entity);
//Add the CIMFilteredFindPathsEntity to the DestinationEntities collection
ffp_config.DestinationEntities = destEntities.ToArray();
//Path Filters
ffp_config.PathFilters = [];//Empty
//Traversal
ffp_config.TraversalDirections = [];//Empty
//Other
ffp_config.RelationshipCostProperty = "";
ffp_config.DefaultRelationshipCost = 1.0;
ffp_config.DefaultTraversalDirectionType = KGTraversalDirectionType.Any;
ffp_config.EntityUsage = FilteredFindPathsEntityUsage.AnyOriginAnyDestination;
ffp_config.PathMode = KGPathMode.Shortest;
ffp_config.MinPathLength = (int)1;//Min number of relationships in path
ffp_config.MaxPathLength = (int)8;//Max number of relationships in path
ffp_config.MaxCountPaths = (int)100000;//Total number of paths to return
ffp_config.ClosedPathPolicy = KGClosedPathPolicy.Forbid;
ffp_config.TimeFilter = null;
var results = kg.RunFilteredFindPaths(ffp_config);
//TODO process/analyze results
});
//using ArcGIS.Core.Data.Knowledge.Extensions;
await QueuedTask.Run(async() =>
{
var ffp_config = new CIMFilteredFindPathsConfiguration();
ffp_config.Name = "Create Link Chart from FFP Results";
//set up config
//...
var results = kg.RunFilteredFindPaths(ffp_config);
var pathsEntitiesAndRelationships = results.ExtractPathsEntitiesAndRelationships(null);
//Create a KG layer id set
var kgLayerIdSet = KnowledgeGraphLayerIDSet.FromKnowledgeGraphIDSet(
pathsEntitiesAndRelationships.ToKnowledgeGraphIDSet(
KGResultContentFromFFP.EntitiesAndRelationships));
//Create a brand new link chart with the results and show it
var linkChart = MapFactory.Instance.CreateLinkChart(
"KG Intro", kg, kgLayerIdSet);
var mapPane = await FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);
var linkChartView = mapPane.MapView;
//Change layout algo to match the default used by the UI after FFP
await linkChartView.SetLinkChartLayoutAsync(
KnowledgeLinkChartLayoutAlgorithm.Hierarchical_TopToBottom);
//Set root nodes - they correspond to the origin nodes of the result paths
var kgLayerIdSetForRootNodes = KnowledgeGraphLayerIDSet.FromKnowledgeGraphIDSet(
pathsEntitiesAndRelationships.ToKnowledgeGraphIDSet(
KGResultContentFromFFP.OnlyPathsOriginEntities));
//To correctly identify the ids in the link chart we must change the ids
//from Geodatabase oids returned in the KnowledgeGraphLayerIDSet to the
//temporary/synthetic oids used by layers in the link chart...
var kg_layer = linkChart.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().First();
var mapMembers = kg_layer.GetMapMembersAsFlattenedList();
var oidDict = kgLayerIdSetForRootNodes.ToOIDDictionary();
var mmDict = new Dictionary<MapMember, List<long>>();
foreach (var kvp in oidDict)
{
var named_type = kvp.Key;
foreach (var mm in mapMembers)
{
if (mm is LinkChartFeatureLayer fl_lc && fl_lc.IsEntity)
{
if (fl_lc.GetTypeName().ToLower() == named_type.ToLower())
{
var lc_oids = new List<long>();
//these oids are from the geodatabase
var oid_field = $"{fl_lc.GetTypeName()}.objectid";
var id_list = string.Join(',', kvp.Value.ToArray());
var where = $"{fl_lc.GetTypeName()}.objectid IN ({id_list})";
var qf = new ArcGIS.Core.Data.QueryFilter()
{
WhereClause = where,
SubFields = $"LC.OID,{oid_field}"//the 'LC.OID' oids are the ones
//we need for the mapmember id set
//in the link chart
};
var rc = fl_lc.Search(qf);
var oid_idx = rc.FindField(oid_field);
while (rc.MoveNext())
{
var oid = (long)rc.Current[oid_idx];
var lc_oid = rc.Current.GetObjectID();
lc_oids.Add(lc_oid);
}
rc.Dispose();
mmDict[fl_lc] = lc_oids;
break;
}
}
}
}
var mmIdSet = MapMemberIDSet.FromDictionary(mmDict);
linkChartView.SetRootNodes(mmIdSet);
});
//using ArcGIS.Core.Data.Knowledge.Extensions; var linkChartView = MapView.Active; await QueuedTask.Run(async () => { var ffp_config = new CIMFilteredFindPathsConfiguration(); ffp_config.Name = "Append to Link Chart from FFP Results"; //set up config //... var results = kg.RunFilteredFindPaths(ffp_config); var pathsEntitiesAndRelationships = results.ExtractPathsEntitiesAndRelationships(null); //Create a KG layer id set var kgLayerIdSet = KnowledgeGraphLayerIDSet.FromKnowledgeGraphIDSet( pathsEntitiesAndRelationships.ToKnowledgeGraphIDSet( KGResultContentFromFFP.EntitiesAndRelationships)); var map = linkChartView.Map; if (!map.CanAppendToLinkChart(kgLayerIdSet)) return;//not compatible map.AppendToLinkChart(kgLayerIdSet); //switch layout algo var algo = linkChartView.GetLinkChartLayout(); if (algo != KnowledgeLinkChartLayoutAlgorithm.Hierarchical_TopToBottom) { //Change layout algo to match the default used by the UI after FFP await linkChartView.SetLinkChartLayoutAsync( KnowledgeLinkChartLayoutAlgorithm.Hierarchical_TopToBottom); } //To set link chart root nodes see 'Create Link Chart from FFP Results' });
//using ArcGIS.Core.Data.Knowledge.Extensions;
await QueuedTask.Run(async () =>
{
var ffp_config = new CIMFilteredFindPathsConfiguration();
ffp_config.Name = "List out FFP Results by Path Length, Min Cost, Max Cost";
//set up config
//...
var results = kg.RunFilteredFindPaths(ffp_config);
if (results.CountPaths == 0)
{
System.Diagnostics.Debug.WriteLine("FFP returned no paths");
return;
}
//print out paths by increasing length, min cost, max cost
var path_by_len_indices = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingPathLength
.Select(idx => idx.index);
var path_by_min_cost = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingMinPathCost
.Select(idx => idx.index);
var path_by_max_cost = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingMaxPathCost
.Select(idx => idx.index);
var x = 0;
StringBuilder sb = new StringBuilder();
foreach (var path_indeces in new List<IEnumerable<long>> {
path_by_len_indices,
path_by_min_cost,
path_by_max_cost})
{
if (x == 0)
sb.AppendLine($"Paths by length: {path_by_len_indices.Count()}");
else if (x == 1)
sb.AppendLine($"Paths by min cost: {path_by_min_cost.Count()}");
else if (x == 2)
sb.AppendLine($"Paths by max cost: {path_by_max_cost.Count()}");
x++;
foreach (var path_idx in path_indeces)
{
var path = (ResultPath)results.MaterializePath(path_idx);
sb.AppendLine(
$"Path[{path_idx}] length: {path.Length}, min: {path.MinCost} max: {path.MaxCost}");
var g = 0;
foreach (var rel_group in path.RelationshipGroups)
{
var first_entity = $"({rel_group.FirstEntity.TypeName}:{rel_group.FirstEntity.Uid})";
var second_entity = $"({rel_group.SecondEntity.TypeName}:{rel_group.SecondEntity.Uid})";
foreach (var relation in rel_group.Relationships)
{
sb.Append($" [{g++}] ");
var arrow = relation.SameDirectionAsPath ? "->" : "<-";
var rel_uid = FormatID(relation.Relationship.Uid.ToString());
sb.Append($"{first_entity} '\r\n\t{relation.Relationship.TypeName}:{rel_uid}' {arrow}\r\n" +
$"\t\t{second_entity}");
sb.Append($" cost: {relation.Relationship.Cost}\r\n");
}
}
}
}
});
string FormatID(string id)
{
id = id.ToUpperInvariant();
if (!id.StartsWith('{'))
id = '{' + id;
if (!id.EndsWith('}'))
id += '}';
return id;
}
//using ArcGIS.Core.Data.Knowledge.Extensions; await QueuedTask.Run(async () => { var ffp_config = new CIMFilteredFindPathsConfiguration(); ffp_config.Name = "List out FFP Results Origin, Destination, Other Entities"; //set up config //... var results = kg.RunFilteredFindPaths(ffp_config); if (results.CountPaths == 0) { System.Diagnostics.Debug.WriteLine("FFP returned no paths"); return; } //print out paths by increasing length, min cost, max cost var path_by_len_indices = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingPathLength .Select(idx => idx.index); var path_by_min_cost = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingMinPathCost .Select(idx => idx.index); var path_by_max_cost = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingMaxPathCost .Select(idx => idx.index); var x = 0; StringBuilder sb = new StringBuilder(); foreach (var path_indeces in new List<IEnumerable<long>> { path_by_len_indices, path_by_min_cost, path_by_max_cost}) { if (x == 0) sb.AppendLine($"Entities by length: {path_by_len_indices.Count()}"); else if (x == 1) sb.AppendLine($"Entities by min cost: {path_by_min_cost.Count()}"); else if (x == 2) sb.AppendLine($"Entities by max cost: {path_by_max_cost.Count()}"); x++; foreach (var path_idx in path_indeces) { var path = (ResultPath)results.MaterializePath(path_idx); sb.AppendLine( $"Path[{path_idx}] length: {path.Length}, min: {path.MinCost} max: {path.MaxCost}"); var sorted_set = new SortedSet<ulong>(); sorted_set.Add((ulong)path_idx); var per = results.ExtractPathsEntitiesAndRelationships(sorted_set); var origin_dest_uids = new List<string>(); var sep = ""; sb.Append(" Origin EntitiesUIDs: "); foreach (var idx in per.PathsOriginEntitiesUIDsIndexes) { //See 'List out FFP Results by Path Length, Min Cost, Max Cost' for //FormatID method above var uid = FormatID(per.EntitiesUIDs[idx].ToString()); origin_dest_uids.Add(uid); var origin = $"{sep}{per.EntityTypeNames[per.EntityTypes[idx]]}:{uid}"; sep = ", "; sb.Append($"{origin}"); } sb.AppendLine(""); sep = ""; sb.Append(" Destination EntitiesUIDs: "); foreach (var idx in per.PathsDestinationEntitiesUIDsIndexes) { var uid = FormatID(per.EntitiesUIDs[idx].ToString()); origin_dest_uids.Add(uid); var dest = $"{sep}{per.EntityTypeNames[per.EntityTypes[idx]]}:{uid}"; sep = ", "; sb.Append($"{dest}"); } sb.AppendLine(""); sep = ""; var idx2 = 0; sb.Append(" Other EntitiesUIDs: "); bool wereAnyOthers = false; foreach (var raw_uid in per.EntitiesUIDs) { var uid = FormatID(raw_uid.ToString()); if (!origin_dest_uids.Contains(uid)) { var other = $"{sep}{per.EntityTypeNames[per.EntityTypes[idx2]]}:{uid}"; sep = ", "; sb.Append($"{other}"); wereAnyOthers = true; } idx2++; } if (!wereAnyOthers) sb.Append(" <<none>>"); //sb.AppendLine(""); var entity_str = sb.ToString(); System.Diagnostics.Debug.WriteLine(entity_str); sb.Clear(); sep = ""; } } });
//using ArcGIS.Core.Data.Knowledge.Extensions; await QueuedTask.Run(async () => { var ffp_config = new CIMFilteredFindPathsConfiguration(); ffp_config.Name = "List out FFP Results Relationships"; //set up config //... var results = kg.RunFilteredFindPaths(ffp_config); if (results.CountPaths == 0) { System.Diagnostics.Debug.WriteLine("FFP returned no paths"); return; } //print out paths by increasing length, min cost, max cost var path_by_len_indices = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingPathLength .Select(idx => idx.index); var path_by_min_cost = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingMinPathCost .Select(idx => idx.index); var path_by_max_cost = (IEnumerable<long>)results.PathIndicesOrderedByIncreasingMaxPathCost .Select(idx => idx.index); var x = 0; StringBuilder sb = new StringBuilder(); foreach (var path_indeces in new List<IEnumerable<long>> { path_by_len_indices, path_by_min_cost, path_by_max_cost}) { if (x == 0) sb.AppendLine($"Relationships by length: {path_by_len_indices.Count()}"); else if (x == 1) sb.AppendLine($"Relationships by min cost: {path_by_min_cost.Count()}"); else if (x == 2) sb.AppendLine($"Relationships by max cost: {path_by_max_cost.Count()}"); x++; foreach (var path_idx in path_indeces) { var path = (ResultPath)results.MaterializePath(path_idx); sb.AppendLine( $"Path[{path_idx}] length: {path.Length}, min: {path.MinCost} max: {path.MaxCost}"); var sorted_set = new SortedSet<ulong>(); sorted_set.Add((ulong)path_idx); var per = results.ExtractPathsEntitiesAndRelationships(sorted_set); var idx = 0; foreach (var rel_uid in per.RelationshipsUIDs) { sb.Append($" RelationshipsUIDs[{idx}]: "); var uid = FormatID(rel_uid.ToString()); var rel_info = $"{per.RelationshipTypeNames[per.RelationshipTypes[idx]]}:{uid}"; sb.Append($"{rel_info}\r\n"); //From entity: var entity_idx = per.RelationshipsFrom[idx]; var origin_uid = FormatID(per.EntitiesUIDs[entity_idx].ToString()); var origin = $"{per.EntityTypeNames[per.EntityTypes[entity_idx]]}:{origin_uid}"; sb.Append($" RelationshipsFrom: {origin}\r\n"); //To entity entity_idx = per.RelationshipsTo[idx]; var dest_uid = FormatID(per.EntitiesUIDs[entity_idx].ToString()); var dest = $"{per.EntityTypeNames[per.EntityTypes[entity_idx]]}:{dest_uid}"; sb.Append($" RelationshipsTo: {dest}\r\n"); idx++; } var rel_str = sb.ToString(); System.Diagnostics.Debug.WriteLine(rel_str); sb.Clear(); } } });
System.Object
ArcGIS.Core.Data.Knowledge.Analytics.KnowledgeGraphFilteredFindPathsResults
Target Platforms: Windows 11, Windows 10