ArcGIS Pro 3.6 API Reference Guide
ArcGIS.Core.Data.Knowledge.Analytics Namespace / KnowledgeGraphFilteredFindPathsResults Class
Members Example

In This Topic
    KnowledgeGraphFilteredFindPathsResults Class
    In This Topic
    Gives access to paths found by the Filtered Find Paths algorithm, as well as pathfinding warnings and statistics.
    Object Model
    KnowledgeGraphFilteredFindPathsResults ClassPathsEntitiesAndRelationships Class
    Syntax
    public class KnowledgeGraphFilteredFindPathsResults 
    Public Class KnowledgeGraphFilteredFindPathsResults 
    Remarks
    Individual paths can be materialized using MaterializePath.

    For performance, if you are only interested in the entities and relationships of paths, use ExtractPathsEntitiesAndRelationships instead of materializing paths.

    Example
    Run FFP Using Defaults
          //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
          });
    Create Link Chart from FFP 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);
        });
    Append to Link Chart from FFP Results
    //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'
    });
    List out FFP Results by Path Length, Min Cost, Max Cost
        //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;
        }
    List out FFP Results Origin, Destination, Other Entities
    //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 = "";
            }
        }
    
    });
    
    List out FFP Results Relationships
    //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();
            }
        }
    
    });
    
    Inheritance Hierarchy

    System.Object
       ArcGIS.Core.Data.Knowledge.Analytics.KnowledgeGraphFilteredFindPathsResults

    Requirements

    Target Platforms: Windows 11, Windows 10

    ArcGIS Pro version: 3.6 or higher.
    See Also