awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));try{//Open a connectionusing(varkg=newKnowledgeGraph(kg_props)){//TODO...use the KnowledgeGraph}}catch(GeodatabaseNotFoundOrOpenedExceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}});
Getting a Connection from a KnowledgeGraphLayer
//var kgLayer = MapView.Active.Map.GetLayersAsFlattenedList()// .OfType<KnowledgeGraphLayer>().FirstOrDefault();awaitQueuedTask.Run(()=>{// use the layer directlyKnowledgeGraphdatastore=kgLayer.GetDatastore();// or you can use any of the sub items since//KnowledgeGraphLayer is a composite layer - get the first // child feature layer or standalone tablevarfeatlayer=kgLayer?.GetLayersAsFlattenedList()?.OfType<FeatureLayer>()?.FirstOrDefault();KnowledgeGraphkg=null;if(featlayer!=null){using(varfc=featlayer.GetFeatureClass())kg=fc.GetDatastore()asKnowledgeGraph;//TODO use KnowledgeGraph}else{//try standalone tablevarstbl=kgLayer?.GetStandaloneTablesAsFlattenedList()?.FirstOrDefault();if(stbl!=null){using(vartbl=stbl.GetTable())kg=tbl.GetDatastore()asKnowledgeGraph;//TODO use KnowledgeGraph}}});
Retrieving GDB FeatureClasses and Definitions
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(kg_props)){//Get the featureclass definitions from the KG datastorevarfc_defs=kg.GetDefinitions<FeatureClassDefinition>();//For each feature class definition, get the corresponding//feature class. Note: The name of the feature class will match //the name of its corresponding KnowledgeGraph named object type//in the KnowledgeGraph graph data modelforeach(varfc_definfc_defs){varfc_name=fc_def.GetName();using(varfc=kg.OpenDataset<FeatureClass>(fc_name)){//TODO - use the feature class}}}});
Retrieving GDB Tables and Definitions
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(kg_props)){//Get the table definitions from the KG datastorevartbl_defs=kg.GetDefinitions<TableDefinition>();//For each table definition, get the corresponding//table. Note: The name of the table will match the name//of its corresponding KnowledgeGraph named object type in//the KnowledgeGraph graph data modelforeach(vartbl_defintbl_defs){vartbl_name=tbl_def.GetName();using(varfc=kg.OpenDataset<Table>(tbl_name)){//TODO - use the table}}}});
Get service Uri from KG datastore
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(kg_props)){varconnector=kg.GetConnector()asKnowledgeGraphConnectionProperties;varuri=connector.URL;varserviceUri=uri.AbsoluteUri;}});
Transform a set of objectIDs to IDs for an entity
awaitQueuedTask.Run(()=>{varkg_props=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(kg_props)){stringentityName="Name-of-the-entity";varoidList=newList<long>(){260294,678,3523,3,669,93754};varidList=kg.TransformToIDs(entityName,oidList);}});
Transform a set of IDs to objectIDs for an entity
awaitQueuedTask.Run(()=>{varidList=newList<object>(){"{CA2EF786-A10E-4B40-9737-9BDDDEA127B0}","{14B5AD65-890D-4062-90A7-C42C23B0066E}","{A428D1F6-CB00-4559-AAFD-40885A4F2340}"};varkg_props=newKnowledgeGraphConnectionProperties(newUri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=newKnowledgeGraph(kg_props)){stringentityName="Name-of-the-entity";varoidList=kg.TransformToObjectIDs(entityName,idList);}});
KnowledgeGraph Graph Data Model
Retrieving the Data Model
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){//TODO use KG data model...}}});
Get Data Model Properties
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){varkg_name=System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(kg_props.URL.ToString()));System.Diagnostics.Debug.WriteLine($"\r\n'{kg_name}' Datamodel:\r\n-----------------");vartime_stamp=kg_dm.GetTimestamp();varsr=kg_dm.GetSpatialReference();System.Diagnostics.Debug.WriteLine($"Timestamp: {time_stamp}");System.Diagnostics.Debug.WriteLine($"Sref: {sr.Wkid}");System.Diagnostics.Debug.WriteLine($"IsStrict: {kg_dm.GetIsStrict()}");System.Diagnostics.Debug.WriteLine($"OIDPropertyName: {kg_dm.GetOIDPropertyName()}");System.Diagnostics.Debug.WriteLine($"IsArcGISManaged: {kg_dm.GetIsArcGISManaged()}");}}});
Get Data Model Identifier Info
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){varkg_id_info=kg_dm.GetIdentifierInfo();varkg_id_gen=kg_id_info.GetIdentifierGeneration();if(kg_id_infoisKnowledgeGraphNativeIdentifierkg_ni){System.Diagnostics.Debug.WriteLine($"IdentifierInfo: KnowledgeGraphNativeIdentifier");}elseif(kg_id_infoisKnowledgeGraphUniformIdentifierkg_ui){System.Diagnostics.Debug.WriteLine($"IdentifierInfo: KnowledgeGraphUniformIdentifier");System.Diagnostics.Debug.WriteLine($"IdentifierName: '{kg_ui.GetIdentifierName()}'");}System.Diagnostics.Debug.WriteLine($"Identifier MethodHint: {kg_id_gen.GetMethodHint()}");}}});
Get Data Model MetaEntityTypes/Provenance
//Provenance entity type is stored as a MetaEntityType QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){vardict_types=kg_dm.GetMetaEntityTypes();//If there is no provenance then MetaEntityTypes will be//an empty collectionforeach(varkvpindict_types){varmeta_entity_type=kvp.Value;if(meta_entity_type.GetRole()==KnowledgeGraphNamedObjectTypeRole.Provenance){//TODO - use the provenance entity typevarname=meta_entity_type.GetName();}}}}});
Get KnowledgeGraph Entity Types
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){vardict_types=kg_dm.GetEntityTypes();foreach(varkvpindict_types){varentity_type=kvp.Value;varrole=entity_type.GetRole();//note "name" will be the same name as the corresponding//feature class or table in the KG's relational gdb modelvarname=entity_type.GetName();varalias=entity_type.GetAliasName();varobjectIDPropertyName=entity_type.GetObjectIDPropertyName();//etc}}}});
Get the KG Provenance using KnowledgeGraphPropertyInfo
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){// use the KnowledgeGraphPropertyInfovarpropInfo=kg.GetPropertyNameInfo();varsupportsProvenance=propInfo.SupportsProvenance;varprovenanceType=propInfo.ProvenanceTypeName;varprovenanceInfo=propInfo.ProvenancePropertyInfo;}});
Get Whether KG Supports Provenance
stringGetProvenanceEntityTypeName(KnowledgeGraphDataModelkg_dm){varentity_types=kg_dm.GetMetaEntityTypes();foreach(varentity_typeinentity_types){if(entity_type.Value.GetRole()==KnowledgeGraphNamedObjectTypeRole.Provenance)returnentity_type.Value.GetName();}return"";}boolKnowledgeGraphSupportsProvenance(KnowledgeGraphkg){//if there is a provenance entity type then the KnowledgeGraph//supports provenancereturn!string.IsNullOrEmpty(GetProvenanceEntityTypeName(kg.GetDataModel()));// OR use the KnowledgeGraphPropertyInfovarpropInfo=kg.GetPropertyNameInfo();returnpropInfo.SupportsProvenance;}
Get the KG Document info using KnowledgeGraphPropertyInfo
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){// use the KnowledgeGraphPropertyInfovarpropInfo=kg.GetPropertyNameInfo();varsupportsDocs=propInfo.SupportsDocuments;vardocumentType=propInfo.DocumentTypeName;varhasDocumentType=propInfo.HasDocumentTypeName;// available at Pro 3.6 onlyvardocumentInfo=propInfo.DocumentPropertyInfo;}});
Get Whether KG Has a Document Type
stringGetDocumentEntityTypeName(KnowledgeGraphDataModelkg_dm){varentity_types=kg_dm.GetEntityTypes();foreach(varentity_typeinentity_types){varrole=entity_type.Value.GetRole();if(role==KnowledgeGraphNamedObjectTypeRole.Document)returnentity_type.Value.GetName();}return"";//Unusual - probably Neo4j user-managed}boolKnowledgeGraphHasDocumentType(KnowledgeGraphkg){//uncommon for there not to be a document typereturn!string.IsNullOrEmpty(GetDocumentEntityTypeName(kg.GetDataModel()));// OR use the KnowledgeGraphPropertyInfovarpropInfo=kg.GetPropertyNameInfo();returnpropInfo.SupportsDocuments;}
Check Whether A KG Entity Is a Document
//Use GetDocumentEntityTypeName(KnowledgeGraphDataModel kg_dm) from//the 'Get Whether KG Has a Document Type' snippet to//get the documentNameType parameterboolGetEntityIsDocument(KnowledgeGraphEntityValueentity,stringdocumentNameType=""){if(string.IsNullOrEmpty(documentNameType))returnfalse;returnentity.GetTypeName()==documentNameType;}
Check Whether A Graph Type has a Spatial Property
//Use GetDocumentEntityTypeName(KnowledgeGraphDataModel kg_dm) from//the 'Get Whether KG Has a Document Type' snippet to//get the documentNameType parameterboolHasGeometry(KnowledgeGraphNamedObjectTypekg_named_obj){varprops=kg_named_obj.GetProperties();returnprops.Any(prop =>prop.FieldType==FieldType.Geometry);}
Get KnowledgeGraph Relationship Types
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm=kg.GetDataModel()){vardict_types=kg_dm.GetRelationshipTypes();foreach(varkvpindict_types){varrel_type=kvp.Value;varrole=rel_type.GetRole();//note "name" will be the same name as the corresponding//feature class or table in the KG's relational gdb modelvarname=rel_type.GetName();//etc.//Get relationship end pointsvarend_points=rel_type.GetEndPoints();foreach(varend_pointinend_points){System.Diagnostics.Debug.WriteLine($"Origin: '{end_point.GetOriginEntityTypeName()}', "+$"Destination: '{end_point.GetDestinationEntityTypeName()}'");}}}}});
Get All KnowledgeGraph Graph Types
awaitQueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=newKnowledgeGraphConnectionProperties(newUri(url));using(varkg=newKnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_datamodel=kg.GetDataModel()){varentities=kg_datamodel.GetEntityTypes();varrelationships=kg_datamodel.GetRelationshipTypes();varprovenance=kg_datamodel.GetMetaEntityTypes();varall_graph_types=newList<KnowledgeGraphNamedObjectType>();all_graph_types.AddRange(entities.Values);all_graph_types.AddRange(relationships.Values);all_graph_types.AddRange(provenance.Values);System.Diagnostics.Debug.WriteLine("\r\nGraph Types");intc=0;foreach(vargraph_typeinall_graph_types){vartype_name=graph_type.GetName();varrole=graph_type.GetRole().ToString();//equivalent to://var fields = featClassDef.GetFields().Select(f => f.Name).ToList();//var field_names = string.Join(",", fields);varprops=graph_type.GetProperties().Select(p =>p.Name).ToList();varprop_names=string.Join(",",props);System.Diagnostics.Debug.WriteLine($"[{c++}]: "+$"{type_name}, {role}, {prop_names}");}}}});
KnowledgeGraph Investigations
Create an Investigation
awaitQueuedTask.Run(()=>{varinvestigation=KnowledgeGraphInvestigationFactory.Instance.CreateInvestigation(url,"myInvestigation");//TODO - use the investigation});
// open an existing investigationvarinvestigationProjectItems=Project.Current.GetItems<KnowledgeGraphInvestigationProjectItem>();varinvestigationProjectItem=investigationProjectItems.FirstOrDefault(ipi =>ipi.Name.Equals("myInvestigation"));awaitQueuedTask.Run(()=>{KnowledgeGraphInvestigationinvestigation=investigationProjectItem.GetInvestigation();ProApp.Panes.CreateInvestigationPaneAsync(investigation);});
Get the Knowlege Graph Investigation container
varcontainerPath="KnowledgeGraph";// find the first container with the correct path (key)varinvContainer=Project.Current.ProjectItemContainers.FirstOrDefault(c =>c.Path==containerPath);
Select an investigation in the catalog pane
varinvestigationContainer=Project.Current.GetProjectItemContainer("KnowledgeGraph");varitem=Project.Current.GetItems<KnowledgeGraphInvestigationProjectItem>().FirstOrDefault();//Select the fcif(item!=null){varprojectWindow=Project.GetCatalogPane();awaitprojectWindow.SelectItemAsync(item,true,true,investigationContainer);}
KnowledgeGraphInvestigationView
Get the active KnowledgeGraphInvestigationView, KnowledgeGraphInvestigation
// access the currently active knowledge graph investigation viewKnowledgeGraphInvestigationViewactiveView=KnowledgeGraphInvestigationView.Active;KnowledgeGraphInvestigationinvestigation=activeView?.Investigation;if(investigation!=null){// perform some action}
Activate an existing investigation view
//Confirm if investigation exists as a project itemKnowledgeGraphInvestigationProjectIteminvestigationItem=Project.Current.GetItems<KnowledgeGraphInvestigationProjectItem>().FirstOrDefault(
item =>item.Name.Equals("myInvestigation"));if(investigationItem!=null){KnowledgeGraphInvestigationinvestigation=awaitQueuedTask.Run(()=>investigationItem.GetInvestigation());// see if a view is already open that references the same investigationforeach(varinvestigationPaneinProApp.Panes.OfType<IKnowledgeGraphInvestigationPane>()){//if there is a match, activate the viewif(investigationPane.InvestigationView.Investigation==investigation){(investigationPaneasPane).Activate();return;}}}
Select entity, relationship types in an investigation view
// get the active investigation viewvariv=KnowledgeGraphInvestigationView.Active;// clear any TOC selectioniv.ClearTOCSelection();// select entitiesList<string>entities=newList<string>();entities.Add("Person");entities.Add("Org");iv.SelectEntities(entities);// or select relationshipsList<string>relationships=newList<string>();relationships.Add("HasEmployee");iv.SelectRelationships(relationships);// or select a combinationList<string>namedObjectTypes=newList<string>();namedObjectTypes.Add("Person");namedObjectTypes.Add("Org");namedObjectTypes.Add("HasEmployee");iv.SelectNamedObjectTypes(namedObjectTypes);
Select records in an investigation view
// get the active investigation view variv=KnowledgeGraphInvestigationView.Active;varserviceUri=iv.Investigation.ServiceUri;// build a dictionary of recordsstringsome_entity="Entity_Type_Name";vardict=newDictionary<string,List<long>>();//Each entry consists of the type name and corresponding lists of idsdict.Add(some_entity,newList<long>(){1,5,18,36,78});//Create the id set...varidSet=KnowledgeGraphLayerIDSet.FromDictionary(newUri(serviceUri),dict);// select the records on the investigation viewiv.SetSelectedRecords(idSet,SelectionCombinationMethod.New);
Get Selected records and open in a new link chart
// get the active investigation viewvariv=KnowledgeGraphInvestigationView.Active;awaitQueuedTask.Run(()=>{// get the investigationvarinv=iv.Investigation;// get the set of selected recordsvaridSet=iv.GetSelectedRecords();// view these records in a link chartvarmap=MapFactory.Instance.CreateLinkChart("myLinkChart",newUri(inv.ServiceUri),idSet);ProApp.Panes.CreateMapPaneAsync(map);});
KnowledgeGraphLayer Creation with Maps
Create a KG Layer containing all Entity and Relate types
awaitQueuedTask.Run(()=>{//With a connection to a KG established or source uri available...//Create a KnowledgeGraphLayerCreationParamsvarkg_params=newKnowledgeGraphLayerCreationParams(kg){Name="KG_With_All_Types",IsVisible=false};//Orvarkg_params2=newKnowledgeGraphLayerCreationParams(newUri(url)){Name="KG_With_All_Types",IsVisible=false};//Call layer factory with map or group layer container. //A KG layer containing a feature layer and/or standalone table per//entity and relate type (except provenance) is createdvarkg_layer=LayerFactory.Instance.CreateLayer<KnowledgeGraphLayer>(kg_params,map);});
Create a KG Layer containing a subset of Entity and Relate types
awaitQueuedTask.Run(()=>{//To create a KG layer (on a map or link chart) with a subset of//entities and relates, you must create an "id set". The workflow//is very similar to how you would create a SelectionSet.//First, create a dictionary containing the names of the types to be//added plus a corresponding list of ids (just like with a selection set).//Note: null or an empty list means add all records for "that" type..varkg_datamodel=kg.GetDataModel();//Arbitrarily get the name of the first entity and relate typevarfirst_entity=kg_datamodel.GetEntityTypes().Keys.First();varfirst_relate=kg_datamodel.GetRelationshipTypes().Keys.First();//Make entries in the dictionary for eachvardict=newDictionary<string,List<long>>();dict.Add(first_entity,newList<long>());//Empty list means all recordsdict.Add(first_relate,null);//null list means all records//or specific records - however the ids are obtained//dict.Add(entity_or_relate_name, new List<long>() { 1, 5, 18, 36, 78});//Create the id set...varidSet=KnowledgeGraphLayerIDSet.FromDictionary(kg,dict);//Create the layer params and assign the id setvarkg_params=newKnowledgeGraphLayerCreationParams(kg){Name="KG_With_ID_Set",IsVisible=false,IDSet=idSet};//Call layer factory with map or group layer container//A KG layer containing just the feature layer(s) and/or standalone table(s)//for the entity and/or relate types + associated records will be createdvarkg_layer=LayerFactory.Instance.CreateLayer<KnowledgeGraphLayer>(kg_params,map);});
Using LayerFactory.Instance.CanCreateLayer with KG Create Layer Params
awaitQueuedTask.Run(()=>{//Feature class and/or standalone tables representing KG entity and//relate types can only be added to a map (or link chart) as a child//of a KnowledgeGraph layer....//For example:varfc=kg.OpenDataset<FeatureClass>("Some_Entity_Or_Relate_Name");try{//Attempting to create a feature layer containing the returned fc//is NOT ALLOWED - can only be a child of a KG layervarfl_params_w_kg=newFeatureLayerCreationParams(fc);//CanCreateLayer will return falseif(!(LayerFactory.Instance.CanCreateLayer<FeatureLayer>(fl_params_w_kg,map))){System.Diagnostics.Debug.WriteLine($"Cannot create a feature layer for {fc.GetName()}");return;}//This will throw an exceptionLayerFactory.Instance.CreateLayer<FeatureLayer>(fl_params_w_kg,map);}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}//Can only be added as a child of a parent KGvardict=newDictionary<string,List<long>>();dict.Add(fc.GetName(),newList<long>());varkg_params=newKnowledgeGraphLayerCreationParams(kg){Name=$"KG_With_Just_{fc.GetName()}",IsVisible=false,IDSet=KnowledgeGraphLayerIDSet.FromDictionary(kg,dict)};varkg_layer=LayerFactory.Instance.CreateLayer<KnowledgeGraphLayer>(kg_params,map);});
KnowledgeGraph Layer
Get and Set a KG Layer IDSet
varkg_layer=MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kg_layer==null)return;awaitQueuedTask.Run(()=>{//Get the existing kg layer id set and convert to a dictionaryvarlayer_id_set=kg_layer.GetIDSet();vardict=layer_id_set.ToOIDDictionary();//Empty list means all records//Create an id set from a dictionaryvardict2=newDictionary<string,List<long>>();dict2.Add("Enity_Or_Relate_Type_Name1",null);//Null means all recordsdict2.Add("Enity_Or_Relate_Type_Name2",newList<long>());//Empty list means all recordsdict2.Add("Enity_Or_Relate_Type_Name3",newList<long>(){3,5,9,101,34});//Explicit list of ids//dict2.Add("Enity_Or_Relate_Type_Name4",// new List<long>() { etc, etc });//Create the id setvaridset=KnowledgeGraphLayerIDSet.FromDictionary(kg,dict2);//Can be used to create a layer, link chart, append to link chart, etc...});
Is a dataset part of a Knowledge Graph
varfeatureLyer=MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault();if(featureLyer==null)return;awaitQueuedTask.Run(()=>{//Get the feature classvarfc=featureLyer.GetFeatureClass();// is it part of a KnowledgeGraph?varisPartOfKG=fc.GetIsKnowledgeGraphDataset();});
Get KG Datastore
varkg_layer=MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kg_layer==null)return;awaitQueuedTask.Run(()=>{// get the datastorevarkg=kg_layer.GetDatastore();// now submit a search or a query// kg.SubmitSearch// kg.SubmitQuery});
Get KG Service uri
kgLayer.GetServiceUri();
SubLayers of a KnowledgeGraph Layer
varkg_layer=map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kg_layer==null)return;if(map.MapType==MapType.LinkChart){// if map is of MapType.LinkChart then the first level// children of the kg_layer are of type LinkChartFeatureLayervarchildLayers=kg_layer.Layers;foreach(varchildLayerinchildLayers){if(childLayerisLinkChartFeatureLayerlcFeatureLayer){varisEntity=lcFeatureLayer.IsEntity;varisRel=lcFeatureLayer.IsRelationship;// TODO - continue processing}}}elseif(map.MapType==MapType.Map){// if map is of MapType.Map then the children of the// kg_layer are the standard Featurelayer and StandAloneTablevarchidlren=kg_layer.GetMapMembersAsFlattenedList();foreach(varchildinchidlren){if(childisFeatureLayerfl){// TODO - process the feature layer}elseif(childisStandaloneTablest){// TODO - process the standalone table}}}
Create a LinkChart from a subset of an existing LinkChart IDSet
//var map = ...if(map.MapType!=MapType.LinkChart)return;// find the KG layer//var kgLayer = map.GetLayersAsFlattenedList()// .OfType<KnowledgeGraphLayer>().FirstOrDefault();// find the first LinkChartFeatureLayer in the KG layervarlcFeatureLayer=kgLayer.GetLayersAsFlattenedList().OfType<LinkChartFeatureLayer>().FirstOrDefault();if(lcFeatureLayer!=null)return;awaitQueuedTask.Run(()=>{// get the ID set of the KG layervaridSet=kgLayer.GetIDSet();// get the named object type in the KG that the LinkChartFeatureLayer representsvartypeName=lcFeatureLayer.GetTypeName();// if there are items in the ID Set for this typeif(idSet.Contains(typeName)){// build a new ID set containing only these recordsvardict=idSet.ToOIDDictionary();varoids=dict[typeName];varnewDict=newDictionary<string,List<long>>();newDict.Add(typeName,oids);varnewIDSet=KnowledgeGraphLayerIDSet.FromDictionary(kgLayer.GetDatastore(),newDict);// now create a new link chart using just this subset of recordsMapFactory.Instance.CreateLinkChart("subset LinkChart",kgLayer.GetDatastore(),newIDSet);}});
Graph Query and Text Search
Submit a Graph Query
awaitQueuedTask.Run(async()=>{//and assuming you have established a connection to a knowledge graph//...//Construct an openCypher query - return the first 10 entities (whatever//they are...)varquery="MATCH (n) RETURN n LIMIT 10";//default limit is 100 if not specified//other examples...//query = "MATCH (a:Person) RETURN [a.name, a.age] ORDER BY a.age DESC LIMIT 50";//query = "MATCH (b:Person) RETURN { Xperson: { Xname: b.name, Xage: b.age } } ORDER BY b.name DESC";//query = "MATCH p = (c:Person)-[:HasCar]-() RETURN p ORDER BY c.name DESC";//Create a query filter//Note: OutputSpatialReference is currently ignoredvarkg_qf=newKnowledgeGraphQueryFilter(){QueryText=query};//Optionally - u can choose to include provenance in the results//(_if_ the KG has provenance - otherwise the query will fail)boolincludeProvenanceIfPresent=KnowledgeGraphSupportsProvenance(kg);if(includeProvenanceIfPresent){//Only include if the KG has provenancekg_qf.ProvenanceBehavior=KnowledgeGraphProvenanceBehavior.Include;//default is exclude}//submit the query - returns a KnowledgeGraphCursorusing(varkg_rc=kg.SubmitQuery(kg_qf)){//wait for rows to be returned from the server//note the "await"...while(awaitkg_rc.WaitForRowsAsync()){//Rows have been retrieved - process this "batch"...while(kg_rc.MoveNext()){//Get the current KnowledgeGraphRowusing(vargraph_row=kg_rc.Current){//Graph row is an array, process all returned values...varval_count=(int)graph_row.GetCount();for(inti=0;i<val_count;i++){varretval=graph_row[i];//Process row value (note: recursive)//See "Process a KnowledgeGraphRow Value" snippetProcessKnowledgeGraphRowValue(retval);}}}}//WaitForRowsAsync}//SubmitQuery});
Submit a Text Search
awaitQueuedTask.Run(async()=>{//and assuming you have established a connection to a knowledge graph//...//Construct a KG search filter. Search text uses Apache Lucene Query Parser//syntax - https://lucene.apache.org/core/2_9_4/queryparsersyntax.htmlvarkg_sf=newKnowledgeGraphSearchFilter(){SearchTarget=KnowledgeGraphNamedTypeCategory.Entity,SearchText="Acme Electric Co.",ReturnSearchContext=true,MaxRowCount=10//Default is 100 if not specified};//submit the search - returns a KnowledgeGraphCursorvare=0;using(varkg_rc=kg.SubmitSearch(kg_sf)){//wait for rows to be returned from the server//note the "await"...while(awaitkg_rc.WaitForRowsAsync()){//Rows have been retrieved - process this "batch"...while(kg_rc.MoveNext()){//Get the current KnowledgeGraphRowusing(vargraph_row=kg_rc.Current){//We are returning entities from this searchvarentity=graph_row[0]asKnowledgeGraphEntityValue;varentity_type=entity.GetTypeName();varrecord=newList<string>();//discover keys(aka "fields") dynamically via GetKeysforeach(varprop_nameinentity.GetKeys()){varobj_val=entity[prop_name]??"null";record.Add(obj_val.ToString());}System.Diagnostics.Debug.WriteLine($"{entity_type}[{e++}] "+string.Join(", ",record));//or use "Process a KnowledgeGraphRow Value" snippet//ProcessKnowledgeGraphRowValue(entity);}}}//WaitForRowsAsync}//SubmitSearch});
Convert an Open Cypher Query Result to a Selection
awaitQueuedTask.Run(async()=>{//Given an open-cypher qry against an entity or relationship typevarqry=@"MATCH (p:PhoneNumber) RETURN p LIMIT 10";//create a KG query filtervarkg_qry_filter=newKnowledgeGraphQueryFilter(){QueryText=qry};//save a list of the idsvaroids=newList<long>();using(varkgRowCursor=kg.SubmitQuery(kg_qry_filter)){//wait for rows to be returned asynchronously from the serverwhile(awaitkgRowCursor.WaitForRowsAsync()){//get the rows using "standard" move nextwhile(kgRowCursor.MoveNext()){//current row is accessible via ".Current" prop of the cursorusing(vargraphRow=kgRowCursor.Current){varcell_phone=graphRow[0]asKnowledgeGraphEntityValue;//note: some user-managed graphs do not have objectidsoids.Add(cell_phone.GetObjectID());}}}}//create a query filter using the oidsif(oids.Count>0){//select them on the layervarqf=newQueryFilter(){ObjectIDs=oids//apply the oids to the ObjectIds property};//select the child feature layer or standalone table representing//the given entity or relate type whose records are to be selectedvarphone_number_fl=kgLayer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(l =>l.Name=="PhoneNumber");//perform the selectionphone_number_fl.Select(qf);}});
Use Bind Parameters with an Open Cypher Query
awaitQueuedTask.Run(async()=>{//assume we have, in this case, a list of ids (perhaps retrieved//via a selection, hardcoded (like here), etc.varoids=newList<long>(){3,4,7,8,9,11,12,14,15,19,21,25,29,31,32,36,37,51,53,54,55,56,59,63,75,78,80,84,86,88,96,97,98,101,103,106};//In the query, we refer to the "bind parameter" with the//"$" and a variable name - '$object_ids' in this examplevarqry=@"MATCH (p:PhoneNumber) "+@" WHERE p.objectid IN $object_ids "+@"RETURN p";//we provide the values to be substituted for the variable via the//KnowledgeGraphQueryFilter BindParameter property...varkg_qry_filter=newKnowledgeGraphQueryFilter(){QueryText=qry};//the bind parameter added to the query filter must refer to//the variable name used in the query string (without the "$")//Note://Collections must be converted to a KnowledgeGraphArrayValue before//being assigned to a BindParametervarkg_oid_array=newKnowledgeGraphArrayValue();kg_oid_array.AddRange(oids);oids.Clear();kg_qry_filter.BindParameters["object_ids"]=kg_oid_array;//submit the queryusing(varkgRowCursor=kg.SubmitQuery(kg_qry_filter)){//wait for rows to be returned asynchronously from the serverwhile(awaitkgRowCursor.WaitForRowsAsync()){//get the rows using "standard" move nextwhile(kgRowCursor.MoveNext()){//current row is accessible via ".Current" prop of the cursorusing(vargraphRow=kgRowCursor.Current){varcell_phone=graphRow[0]asKnowledgeGraphEntityValue;varoid=cell_phone.GetObjectID();varname=(string)cell_phone["FULL_NAME"];varph_number=(string)cell_phone["PHONE_NUMBER"];System.Diagnostics.Debug.WriteLine($"[{oid}] {name}, {ph_number}");}}}}});
Use Bind Parameters with an Open Cypher Query2
{awaitQueuedTask.Run(async()=>{//assume we have, in this case, a list of ids (perhaps retrieved//via a selection, hardcoded (like here), etc.varoids=newList<long>(){3,4,7,8,9,11,12,14,15,19,21,25,29,31,32,36,37,51,53,54,55,56,59,63,75,78,80,84,86,88,96,97,98,101,103,106};//In the query, we refer to the "bind parameter" with the//"$" and a variable name - '$object_ids' and '$sel_geom'//in this examplevarqry=@"MATCH (p:PhoneNumber) "+@"WHERE p.objectid IN $object_ids AND "+@"esri.graph.ST_Intersects($sel_geom, p.shape) "+@"RETURN p";//create a KG query filtervarkg_qry_filter=newKnowledgeGraphQueryFilter(){QueryText=qry};//the bind parameter added to the query filter must refer to//the variable name used in the query string (without the "$")//Note://Collections must be converted to a KnowledgeGraphArrayValue before//being assigned to a BindParametervarkg_oid_array=newKnowledgeGraphArrayValue();kg_oid_array.AddRange(oids);kg_qry_filter.BindParameters["object_ids"]=kg_oid_array;//Create a polygon based on current map extentvarextent=MapView.Active.Extent;varpoly=PolygonBuilder.CreatePolygon(extent.Expand(0.25,0.25,true));kg_qry_filter.BindParameters["sel_geom"]=poly;oids.Clear();//submit the queryusing(varkgRowCursor=kg.SubmitQuery(kg_qry_filter)){//wait for rows to be returned asynchronously from the serverwhile(awaitkgRowCursor.WaitForRowsAsync()){//get the rows using "standard" move nextwhile(kgRowCursor.MoveNext()){//current row is accessible via ".Current" prop of the cursorusing(vargraphRow=kgRowCursor.Current){
#region Process Row
varcell_phone=graphRow[0]asKnowledgeGraphEntityValue;varoid=cell_phone.GetObjectID();varname=(string)cell_phone["FULL_NAME"];varph_number=(string)cell_phone["PHONE_NUMBER"];System.Diagnostics.Debug.WriteLine($"[{oid}] {name}, {ph_number}");
Call WaitForRowsAsync With Cancellation
//On the QueuedTask...//and assuming you have established a connection to a knowledge graph//...//submit query or search to return a KnowledgeGraphCursor//using (var kgRowCursor = kg.SubmitQuery(kg_qf)) {//using (var kgRowCursor = kg.SubmitSearch(kg_sf)) {//...//wait for rows to be returned from the server//"auto-cancel" after 20 secondsvarcancel=newCancellationTokenSource(newTimeSpan(0,0,20));//catch TaskCanceledExceptiontry{while(awaitkgRowCursor.WaitForRowsAsync(cancel.Token)){//check for row eventswhile(kgRowCursor.MoveNext()){using(vargraph_row=kgRowCursor.Current){//Graph row is an array, process all returned values...varval_count=(int)graph_row.GetCount();for(inti=0;i<val_count;i++){varretval=graph_row[i];//Process row value (note: recursive)//See "Process a KnowledgeGraphRow Value" snippetProcessKnowledgeGraphRowValue(retval);}}}}}//Timeout expiredcatch(TaskCanceledExceptiontce){//Handle cancellation as needed}cancel.Dispose();
Process a KnowledgeGraphRow Value
voidProcessGraphNamedObjectValue(KnowledgeGraphNamedObjectValuekg_named_obj_val){if(kg_named_obj_valisKnowledgeGraphEntityValuekg_entity){varlabel=kg_entity.GetLabel();//TODO - use label}elseif(kg_named_obj_valisKnowledgeGraphRelationshipValuekg_rel){varhas_entity_ids=kg_rel.GetHasRelatedEntityIDs();if(kg_rel.GetHasRelatedEntityIDs()){varorigin_id=kg_rel.GetOriginID();vardest_id=kg_rel.GetDestinationID();//TODO - use ids}}varid=kg_named_obj_val.GetID();varoid=kg_named_obj_val.GetObjectID();//Note: Typename corresponds to the name of the feature class or table//in the relational gdb model -and- to the name of the KnowledgeGraphNamedObjectType//in the knowledge graph data modelvartype_name=kg_named_obj_val.GetTypeName();//TODO use id, object id, etc.}//Object values include entities, relationships, and anonymous objectsvoidProcessGraphObjectValue(KnowledgeGraphObjectValuekg_obj_val){switch(kg_obj_val){caseKnowledgeGraphEntityValuekg_entity:ProcessGraphNamedObjectValue(kg_entity);break;caseKnowledgeGraphRelationshipValuekg_rel:ProcessGraphNamedObjectValue(kg_rel);break;default://Anonymous objectsbreak;}//graph object values have a set of properties (equivalent//to a collection of key/value pairs)varkeys=kg_obj_val.GetKeys();foreach(varkeyinkeys)ProcessKnowledgeGraphRowValue(kg_obj_val[key]);//Recurse}//Process a KnowledgeGraphValue from a query or searchvoidProcessGraphValue(KnowledgeGraphValuekg_val){switch(kg_val){caseKnowledgeGraphPrimitiveValuekg_prim://KnowledgeGraphPrimitiveValue not currently used in//query and search ProcessKnowledgeGraphRowValue(kg_prim.GetValue());//Recursereturn;caseKnowledgeGraphArrayValuekg_array:varcount=kg_array.GetSize();//Recursively process each value in the arrayfor(ulongi=0;i<count;i++)ProcessKnowledgeGraphRowValue(kg_array[i]);//Recursereturn;caseKnowledgeGraphPathValuekg_path://Entitiesvarentity_count=kg_path.GetEntityCount();//Recursively process each entity value in the pathfor(ulongi=0;i<entity_count;i++)ProcessGraphObjectValue(kg_path.GetEntity(i));//Recurse//Recursively process each relationship value in the pathvarrelate_count=kg_path.GetRelationshipCount();for(ulongi=0;i<relate_count;i++)ProcessGraphObjectValue(kg_path.GetRelationship(i));//Recursereturn;caseKnowledgeGraphObjectValuekg_object:ProcessGraphObjectValue(kg_object);//Recursereturn;default:vartype_string=kg_val.GetType().ToString();System.Diagnostics.Debug.WriteLine($"Unknown: '{type_string}'");return;}}//Process each value from the KnowledgeGraphRow arrayvoidProcessKnowledgeGraphRowValue(objectvalue){switch(value){//Graph value?caseKnowledgeGraphValuekg_val:varkg_type=kg_val.KnowledgeGraphValueType.ToString();System.Diagnostics.Debug.WriteLine($"KnowledgeGraphValue: '{kg_type}'");ProcessGraphValue(kg_val);//Recursereturn;//Primitive types...add additional logic as neededcaseSystem.DBNulldbn:System.Diagnostics.Debug.WriteLine("DBNull.Value");return;casestringstr:System.Diagnostics.Debug.WriteLine($"'{str}' (string)");return;caselongl_val:System.Diagnostics.Debug.WriteLine($"{l_val} (long)");return;caseinti_val:System.Diagnostics.Debug.WriteLine($"{i_val} (int)");return;caseshorts_val:System.Diagnostics.Debug.WriteLine($"{s_val} (short)");return;casedoubled_val:System.Diagnostics.Debug.WriteLine($"{d_val} (double)");return;casefloatf_val:System.Diagnostics.Debug.WriteLine($"{f_val} (float)");return;caseDateTimedt_val:System.Diagnostics.Debug.WriteLine($"{dt_val} (DateTime)");return;caseDateOnlydt_only_val:System.Diagnostics.Debug.WriteLine($"{dt_only_val} (DateOnly)");return;caseTimeOnlytm_only_val:System.Diagnostics.Debug.WriteLine($"{tm_only_val} (TimeOnly)");return;caseDateTimeOffsetdt_tm_offset_val:System.Diagnostics.Debug.WriteLine($"{dt_tm_offset_val} (DateTimeOffset)");return;caseSystem.Guidguid_val:varguid_string=guid_val.ToString("B");System.Diagnostics.Debug.WriteLine($"'{guid_string}' (Guid)");return;caseGeometrygeom_val:vargeom_type=geom_val.GeometryType.ToString();varis_empty=geom_val.IsEmpty;varwkid=geom_val.SpatialReference?.Wkid??0;System.Diagnostics.Debug.WriteLine($"geometry: {geom_type}, empty: {is_empty}, sr_wkid {wkid} (shape)");return;default://Blob? Others?vartype_str=value.GetType().ToString();System.Diagnostics.Debug.WriteLine($"Primitive: {type_str}");return;}}// ...submit query or search//using (var kgRowCursor = kg.SubmitQuery(kg_qf)) {//using (var kgRowCursor = kg.SubmitSearch(kg_sf)) {// ...wait for rows ...// while (await kgRowCursor.WaitForRowsAsync()) {// ...rows have been retrieved// while (kgRowCursor.MoveNext()) {// ...get the current KnowledgeGraphRow// using (var graph_row = kgRowCursor.Current) {// var val_count = (int)graph_row.GetCount();// for (int i = 0; i<val_count; i++)// ProcessKnowledgeGraphRowValue(graph_row[i]);
Link Charts
Find link chart project items
// find all the link chart project itemsvarlinkChartItems=Project.Current.GetItems<MapProjectItem>().Where(pi =>pi.MapType==MapType.LinkChart);// find a link chart project item by namevarlinkChartItem=Project.Current.GetItems<MapProjectItem>().FirstOrDefault(pi =>pi.Name=="Acme Link Chart");
Find link chart map by name
varprojectItem=Project.Current.GetItems<MapProjectItem>().FirstOrDefault(pi =>pi.Name=="Acme Link Chart");varlinkChartMap=projectItem?.GetMap();
Does Active MapView contain a link chart map
varmv=MapView.Active;// check the viewvarisLinkChartView=mv.IsLinkChartView;// or alternatively get the map and check that//var map = MapView.Active.Map;// check the MapType to determine if it's a link chart mapvarisLinkChart=map.MapType==MapType.LinkChart;// or you could use the following// var isLinkChart = map.IsLinkChart;
Find Link Chart from Map panes
varmapPanes=FrameworkApplication.Panes.OfType<IMapPane>().ToList();varmapPane=mapPanes.FirstOrDefault(
mp =>mp.MapView.IsLinkChartView&&mp.MapView.Map.Name=="Acme Link Chart");varlcMap=mapPane.MapView.Map;
Get and set the link chart layout
//var map = MapView.Active.Map;// a MapView can encapsulate a link chart IF it's map// is of type MapType.LinkChartvarisLinkChart=map.MapType==MapType.LinkChart;// or use the following// var isLinkChart = map.IsLinkChart;varmv=MapView.Active;awaitQueuedTask.Run(()=>{if(isLinkChart){// get the layout algorithmvarlayoutAlgorithm=mv.GetLinkChartLayout();// toggle the valueif(layoutAlgorithm==KnowledgeLinkChartLayoutAlgorithm.Geographic_Organic_Standard)layoutAlgorithm=KnowledgeLinkChartLayoutAlgorithm.Organic_Standard;elselayoutAlgorithm=KnowledgeLinkChartLayoutAlgorithm.Geographic_Organic_Standard;// set itmv.SetLinkChartLayoutAsync(layoutAlgorithm);// OR set it and force a redraw / update// await mv.SetLinkChartLayoutAsync(layoutAlgorithm, true);}});
Create and Append to Link Charts
Create a Link Chart Containing All Records for a KG
awaitQueuedTask.Run(()=>{//Create the link chart and show it//build the IDSet using KnowledgeGraphFilterType.AllNamedObjectsvaridSet=KnowledgeGraphLayerIDSet.FromKnowledgeGraph(kg,KnowledgeGraphFilterType.AllNamedObjects);varlinkChart=MapFactory.Instance.CreateLinkChart("KG Link Chart",kg,idSet);FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);});
Create a Link Chart With an Empty KG Layer
awaitQueuedTask.Run(()=>{//Create the link chart with a -null- id set//This will create a KG Layer with empty sub-layers//(Note: you cannot create an empty KG layer on a map - only on a link chart)varlinkChart=MapFactory.Instance.CreateLinkChart("KG Link Chart",kg,null);FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);});
Create a link chart with all the entities of the Knowledge Graph
awaitQueuedTask.Run(()=>{using(varkg_for_lc=newKnowledgeGraph(newKnowledgeGraphConnectionProperties(newUri(url)))){varidSet=KnowledgeGraphLayerIDSet.FromKnowledgeGraph(kg_for_lc,KnowledgeGraphFilterType.AllEntities);varnewLinkChart=MapFactory.Instance.CreateLinkChart("All_Entities link chart",kg_for_lc,idSet);};});
Create a Link Chart from a query
//use the results of a query to create an idset. Create the link chart//containing just records corresponding to the query resultsvarqry=@"MATCH (p1:PhoneNumber)-[r1:MADE_CALL|RECEIVED_CALL]->(c1:PhoneCall)<-"+@"[r2:MADE_CALL|RECEIVED_CALL]-(p2:PhoneNumber)-[r3:MADE_CALL|RECEIVED_CALL]"+@"->(c2:PhoneCall)<-[r4:MADE_CALL|RECEIVED_CALL]-(p3:PhoneNumber) "+@"WHERE p1.FULL_NAME = ""Robert Johnson"" AND "+@"p3.FULL_NAME= ""Dan Brown"" AND "+@"p1.globalid <> p2.globalid AND "+@"p2.globalid <> p3.globalid "+@"RETURN p1, r1, c1, r2, p2, r3, c2, r4, p3";vardict=newDictionary<string,List<long>>();awaitQueuedTask.Run(async()=>{using(varkg_for_lc=kgLayer.GetDatastore()){vargraphQuery=newKnowledgeGraphQueryFilter(){QueryText=qry};using(varkg_rc=kg_for_lc.SubmitQuery(graphQuery)){while(awaitkg_rc.WaitForRowsAsync()){while(kg_rc.MoveNext()){using(vargraphRow=kg_rc.Current){// process the rowvarcnt_val=(int)graphRow.GetCount();for(intv=0;v<cnt_val;v++){varobj_val=graphRow[v]asKnowledgeGraphNamedObjectValue;vartype_name=obj_val.GetTypeName();varoid=(long)obj_val.GetObjectID();if(!dict.ContainsKey(type_name)){dict[type_name]=newList<long>();}if(!dict[type_name].Contains(oid))dict[type_name].Add(oid);}}}}}//make an ID Set to create the LinkChartvaridSet=KnowledgeGraphLayerIDSet.FromDictionary(kg_for_lc,dict);//Create the link chart and show itvarlinkChart=MapFactory.Instance.CreateLinkChart("KG With ID Set",kg_for_lc,idSet);FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);}});
Create a link chart based on a template link chart
// note that the template link chart MUST use the same KG serverawaitQueuedTask.Run(()=>{// find the existing link chart by namevarprojectItem=Project.Current.GetItems<MapProjectItem>().FirstOrDefault(pi =>pi.Name=="Acme Link Chart");varlinkChartMap=projectItem?.GetMap();if(linkChartMap==null)return;//Create a connection propertiesvarkg_props2=newKnowledgeGraphConnectionProperties(newUri(url));try{//Open a connectionusing(varkg_for_lc=newKnowledgeGraph(kg_props2)){//Add all entities to the link chartvaridSet=KnowledgeGraphLayerIDSet.FromKnowledgeGraph(kg_for_lc,KnowledgeGraphFilterType.AllEntities);//Create the new link chart and show itvarnewLinkChart=MapFactory.Instance.CreateLinkChart("KG from Template",kg_for_lc,idSet,linkChartMap.URI);FrameworkApplication.Panes.CreateMapPaneAsync(newLinkChart);}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}});
Checking KnowledgeGraphLayerException
// running on QueuedTaskvardict=newDictionary<string,List<long>>();dict.Add("person",newList<long>());//Empty list means all recordsdict.Add("made_call",null);//null list means all records// or specific records - however the ids are obtaineddict.Add("phone_call",newList<long>(){1,5,18,36,78});// make the id setvaridSet=KnowledgeGraphLayerIDSet.FromDictionary(kg,dict);try{//Create the link chart and show itvarlinkChart=MapFactory.Instance.CreateLinkChart("KG With ID Set",kg,idSet);FrameworkApplication.Panes.CreateMapPaneAsync(linkChart);}catch(KnowledgeGraphLayerExceptione){// get the invalid named types// remember that the named types are case-sensitivevarinvalidNamedTypes=e.InvalidNamedTypes;// do something with the invalid named types // for example - log or return to caller to show message to user}
Append to Link Chart
//We create an id set to contain the records to be appendedvardict=newDictionary<string,List<long>>();dict["Suspects"]=newList<long>();//In this case, via results from a query...varqry2="MATCH (s:Suspects) RETURN s";awaitQueuedTask.Run(async()=>{using(varkg_for_lc=kgLayer.GetDatastore()){vargraphQuery=newKnowledgeGraphQueryFilter(){QueryText=qry2};using(varkg_rc=kg_for_lc.SubmitQuery(graphQuery)){while(awaitkg_rc.WaitForRowsAsync()){while(kg_rc.MoveNext()){using(vargraphRow=kg_rc.Current){varobj_val=graphRow[0]asKnowledgeGraphNamedObjectValue;varoid=(long)obj_val.GetObjectID();dict["Suspects"].Add(oid);}}}}//make an ID Set to append to the LinkChartvaridSet=KnowledgeGraphLayerIDSet.FromDictionary(kg_for_lc,dict);//Get the relevant link chart to which records will be//appended...in this case, from an open map pane in the//Pro application...varmapPanes=FrameworkApplication.Panes.OfType<IMapPane>().ToList();varmapPane=mapPanes.First(
mp =>mp.MapView.IsLinkChartView&&mp.MapView.Map.Name=="Acme Link Chart");varlinkChartMap=mapPane.MapView.Map;//or get the link chart from an item in the catalog...etc.,etc.//var projectItem = Project.Current.GetItems<MapProjectItem>()// .FirstOrDefault(pi => pi.Name == "Acme Link Chart");//var linkChartMap = projectItem?.GetMap();//Call AppendToLinkChart with the id setif(linkChartMap.CanAppendToLinkChart(idSet))linkChartMap.AppendToLinkChart(idSet);}});
ID Sets
Get the ID Set of a KG layer
awaitQueuedTask.Run(()=>{varidSet=kgLayer.GetIDSet();// is the set empty?varisEmpty=idSet.IsEmpty;// get the count of named object typesvarcountNamedObjects=idSet.NamedObjectTypeCount;// does it contain the entity "Species";varcontains=idSet.Contains("Species");// get the idSet as a dictionary of namedObjectType and oidsvaroidDict=idSet.ToOIDDictionary();varspeciesOIDs=oidDict["Species"];// alternatively get the idSet as a dictionary of // namedObjectTypes and uuidsvaruuidDict=idSet.ToUIDDictionary();varspeciesUuids=uuidDict["Species"];});
Create an ID set from a SelectionSet
awaitQueuedTask.Run(()=>{// get the selection setvarsSet=map.GetSelection();// translate to an KnowledgeGraphLayerIDSet// if the selectionset does not contain any KG entity or relationship records// then idSet will be null varidSet=KnowledgeGraphLayerIDSet.FromSelectionSet(sSet);if(idSet==null)return;// you can use the idSet to create a new linkChart// (using MapFactory.Instance.CreateLinkChart)});
awaitQueuedTask.Run(()=>{MapMemberIDSetrootNodes=MapView.Active.GetRootNodes();varrootNodeDict=rootNodes.ToDictionary();// rootNodeDict is a Dictionary<MapMember, List<long>>// access a particular mapMember in the Dictionaryif(rootNodeDict.ContainsKey(mapMember)){varoids=rootNodeDict[mapMember];}// OR iterate through the dictionaryforeach(var(mm,oids)inrootNodeDict){// do something}});
awaitQueuedTask.Run(()=>{varmapSel=MapView.Active.SelectAllRootNodes();// this is the same as MapMemberIDSetrootNodes=MapView.Active.GetRootNodes();SelectionSetselSet=SelectionSet.FromMapMemberIDSet(rootNodes);MapView.Active.Map.SetSelection(selSet);});
awaitQueuedTask.Run(()=>{//Assuming mapview is a link chart viewMapView.Active.ClearRootNodes();});
PrSnippet Group: Non Spatial Data
Non spatial data
awaitQueuedTask.Run(()=>{// display non spatial dataMapView.Active.SetShowNonSpatialData(true);// select the current set of non spatial datavarselNonSpatial=MapView.Active.SelectNonSpatialData();// perform some action// select the current set of spatial datavarselSpatial=MapView.Active.SelectSpatialData();// perform some other action});
Editing
Create a new Entity
varmv=MapView.Active;awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){Name="Create a new organization",SelectNewFeatures=true};//Use datasets or feature layer(s) or standalone table(s)//Get a reference to the KnowledgeGraph//var kg = ... ; //Open the feature class or Table to be editedvarorg_fc=kg.OpenDataset<FeatureClass>("Organization");//Alternatively, use the feature layer for 'Organization' if your context is a map//Get the parent KnowledgeGraphLayervarkg_layer=mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//From the KG Layer get the relevant child feature layervarorg_fl=kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer =>child_layer.Name=="Organization");//Define attributesvarattribs=newDictionary<string,object>();attribs["Name"]="Acme Ltd.";attribs["Description"]="Specializes in household items";attribs["SHAPE"]=mv.Extent.Center;//whatever is its location//Add it to the operation via the dataset...edit_op.Create(org_fc,attribs);//or use the feature layer/stand alone table if preferred and available//edit_op.Create(org_fl, attribs);if(edit_op.Execute()){//TODO: Operation succeeded}});
Create a new Relationship from Existing Entities 1
varcreate_rel=awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){Name="Create a new relationship record",SelectNewFeatures=true};//Use datasets or feature layer(s) or standalone table(s)//Get a reference to the KnowledgeGraph//var kg = ... ; //We will use a relate called 'HasEmployee' to relate an Organization w/ a Person//Use either tables or map members to get the rows to be related...varorg_fc=kg.OpenDataset<FeatureClass>("Organization");varperson_tbl=kg.OpenDataset<Table>("Person");//Get the relationship dataset//We can use either a table or standalone tablevaremp_tbl=kg.OpenDataset<Table>("HasEmployee");//we need the names of the origin and destination relationship propertiesvarkg_prop_info=kg.GetPropertyNameInfo();//Arbitrarily use the first record from the two entity datasets "to be" related//Entities are always related by Global ID. Origin to Destination specifies the//direction (of the relate).////Populate the attributes for the relationshipvarattribs=newDictionary<string,object>();using(varrc=org_fc.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...attribs[kg_prop_info.OriginIDPropertyName]=rc.Current.GetGlobalID();}using(varrc=person_tbl.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...attribs[kg_prop_info.DestinationIDPropertyName]=rc.Current.GetGlobalID();}//Add any extra attribute information for the relation as neededattribs["StartDate"]=newDateTimeOffset(DateTime.Now);//Add a create for the relationship to the operationedit_op.Create(emp_tbl,attribs);//Do the createreturnedit_op.Execute();});
Create a new Relationship from Existing Entities 2
varcreate_rel2=awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){Name="Create a new relationship record",SelectNewFeatures=true};//Use datasets or feature layer(s) or standalone table(s)//Get a reference to the KnowledgeGraph//var kg = ... ; //We will use a relate called 'HasEmployee' to relate an Organization w/ a Person//Use either tables or map members to get the rows to be related...varorg_fc=kg.OpenDataset<FeatureClass>("Organization");varperson_tbl=kg.OpenDataset<Table>("Person");//Get the relationship dataset//We can use either a table or standalone tablevaremp_tbl=kg.OpenDataset<Table>("HasEmployee");// get the origin, destination recordsGuidguidOrigin=Guid.Empty;GuidguidDestination=Guid.Empty;using(varrc=org_fc.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidOrigin=rc.Current.GetGlobalID();}using(varrc=person_tbl.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidDestination=rc.Current.GetGlobalID();}//Add any extra attribute information for the relation as neededvarattribs=newDictionary<string,object>();attribs["StartDate"]=newDateTimeOffset(DateTime.Now);varrd=newKnowledgeGraphRelationshipDescription(guidOrigin,guidDestination,attribs);//Add a create for the relationship to the operationedit_op.Create(emp_tbl,rd);//Do the createreturnedit_op.Execute();});
Create a new Relationship and New Entities 1
varmv=MapView.Active;varcreate_rel1=awaitQueuedTask.Run(()=>{//This example uses a chained edit operationvaredit_op=newEditOperation(){Name="Create entities and a relationship",SelectNewFeatures=true};//We are just going to use the GDB objects in this one but//we could equally use feature layers/standalone tables//using Feature Class/Tables (works within Investigation or map)varorg_fc=kg.OpenDataset<FeatureClass>("Organization");varperson_tbl=kg.OpenDataset<Table>("Person");//Relationship tablevaremp_tbl=kg.OpenDataset<Table>("HasEmployee");varattribs=newDictionary<string,object>();//New Organizationattribs["Name"]="Acme Ltd.";attribs["Description"]="Specializes in household items";attribs["SHAPE"]=mv.Extent.Center;//whatever is its location//Add it to the operation - we need the rowtokenvarrowtoken=edit_op.Create(org_fc,attribs);attribs.Clear();//we are going to re-use the dictionary//New Personattribs["Name"]="Bob";attribs["Age"]="41";attribs["Skills"]="Plumbing, Framing, Flooring";//Add it to the operationvarrowtoken2=edit_op.Create(person_tbl,attribs);attribs.Clear();//At this point we must execute the create of the entitiesif(edit_op.Execute()){//if we are here, the create of the entities was successful//Next, "chain" a second create for the relationship - this ensures that//Both creates (entities _and_ relation) will be -undone- together if needed//....in other words they will behave as if they are a -single- transactionvaredit_op_rel=edit_op.CreateChainedOperation();//we need the names of the origin and destination relation propertiesvarkg_prop_info=kg.GetPropertyNameInfo();//use the row tokens we held on to from the entity createsattribs[kg_prop_info.OriginIDPropertyName]=rowtoken.GlobalID;attribs[kg_prop_info.DestinationIDPropertyName]=rowtoken2.GlobalID;//Add any extra attribute information for the relation as neededattribs["StartDate"]=newDateTimeOffset(DateTime.Now);//Do the create of the relateedit_op_rel.Create(emp_tbl,attribs);returnedit_op_rel.Execute();}returnfalse;//Create of entities failed});
Create a new Relationship and New Entities 2
varmv=MapView.Active;varcreateRel=awaitQueuedTask.Run(()=>{//This example uses a KnowledgeGraphRelationshipDescriptionvaredit_op=newEditOperation(){Name="Create entities and a relationship using a KG relate desc",SelectNewFeatures=true};//We are just going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer=mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//From the KG Layer get the relevant child feature layer(s) and/or standalone//table(s)varorg_fl=kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer =>child_layer.Name=="Organization");varperson_stbl=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="Person");varrel_stbl=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="HasEmployee");varattribs=newDictionary<string,object>();//New Organizationattribs["Name"]="Acme Ltd.";attribs["Description"]="Specializes in household items";attribs["SHAPE"]=mv.Extent.Center;//whatever is its location//Add it to the operation - we need the rowtokenvarrowtoken_org=edit_op.Create(org_fl,attribs);attribs.Clear();//we are going to re-use the dictionary//New Personattribs["Name"]="Bob";attribs["Age"]="41";attribs["Skills"]="Plumbing, Framing, Flooring";//Add it to the operationvarrowtoken_person=edit_op.Create(person_stbl,attribs);attribs.Clear();//Create the new relationship using a KnowledgeGraphRelationshipDescription//Row handles act as the placeholders for the TO BE created new entities that will//be relatedvarsrc_row_handle=newRowHandle(rowtoken_org);vardest_row_handle=newRowHandle(rowtoken_person);//Add any extra attribute information for the relation as neededattribs["StartDate"]=newDateTimeOffset(DateTime.Now);varrel_desc=newKnowledgeGraphRelationshipDescription(src_row_handle,dest_row_handle,attribs);//Add the relate description to the edit operationedit_op.Create(rel_stbl,rel_desc);//Execute the create of the entities and relationshipreturnedit_op.Execute();});
Create a Provenance Record
awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){Name="Create a new provenance record",SelectNewFeatures=true};//lets get the provenance table (provenance is not added to the//map TOC)varprovenance_tbl=kg.OpenDataset<Table>("Provenance");if(provenance_tbl==null)return;//we will add a row to the provenance for person entityvarperson_tbl=kg.OpenDataset<Table>("Person");//Arbitrarily retrieve the first "person" rowvarinstance_id=Guid.Empty;using(varrc=person_tbl.Search()){if(!rc.MoveNext())return;instance_id=rc.Current.GetGlobalID();//Get the global id}//Define the provenance attributes - we need the names//of the provenance properties from the KG ProvenancePropertyInfovarkg_prop_info=kg.GetPropertyNameInfo();varattribs=newDictionary<string,object>();varppi=kg_prop_info.ProvenancePropertyInfo;attribs[ppi.ProvenanceTypeNamePropertyName]=person_tbl.GetDefinition().GetName();//entity type nameattribs[ppi.ProvenanceFieldNamePropertyName]="name";//Must be a property/field on the entityattribs[ppi.ProvenanceSourceNamePropertyName]="Annual Review 2024";//can be anything - can be null//note: Source type is controlled by the CodedValueDomain "esri__provenanceSourceType"attribs[ppi.ProvenanceSourceTypePropertyName]="Document";//one of ["Document", "String", "URL"].attribs[ppi.ProvenanceSourcePropertyName]="HR records";//can be anything, not nullattribs[ppi.ProvenanceCommentPropertyName]="Rock star";//can be anything - can be null//Add in the id of the provenance owner - our "person" in this caseattribs[ppi.ProvenanceInstanceIDPropertyName]=instance_id;//Specify any additional custom attributes added to the provenance//schema by the user as needed....//attribs["custom_attrib"] = "Foo";//attribs["custom_attrib2"] = "Bar";//Create the provenance rowedit_op.Create(provenance_tbl,attribs);if(edit_op.Execute()){//TODO: Operation succeeded}});
Create a Provenance Record 2
awaitQueuedTask.Run(()=>{// check if provenance supportedvarpropInfo=kg.GetPropertyNameInfo();if(!propInfo.SupportsProvenance)return;//Instantiate an operation for the Createvaredit_op=newEditOperation(){Name="Create a new provenance record",SelectNewFeatures=true};varprovName=propInfo.ProvenanceTypeName;//we will add a row to the provenance for person entityvarperson_tbl=kg.OpenDataset<Table>("Person");//Arbitrarily retrieve the first "person" rowvarinstance_id=Guid.Empty;using(varrc=person_tbl.Search()){if(!rc.MoveNext())return;instance_id=rc.Current.GetGlobalID();//Get the global id}varoriginHandle=newRowHandle(person_tbl,instance_id);varpd=newKnowledgeGraphProvenanceDescription(originHandle,"name",KnowledgeGraphSourceType.Document,"Annual Review 2024","HR records","Rock star");//Create the provenance rowedit_op.Create(pd);if(edit_op.Execute()){//TODO: Operation succeeded}});
Create an Entity, a Document, a HasDocument and a Provenance record
awaitQueuedTask.Run(()=>{//Instantiate an operation for the Createvaredit_op=newEditOperation(){Name="Create a records",SelectNewFeatures=true};// create the entityvarpersonToken=edit_op.Create(personLayer,personAtts);// create the documentvarkgDocDesc=newKnowledgeGraphDocumentDescription(@"D:\Data\BirthCertificate.jpg");vardocToken=edit_op.Create(docLayer,kgDocDesc);// create RowHandles from the returned RowTokensvarpersonHandle=newRowHandle(personToken);vardocHandle=newRowHandle(docToken);// create the "hasDocument" relationshipvarrd=newKnowledgeGraphRelationshipDescription(personHandle,docHandle);edit_op.Create(docLayer,rd);// create the provenance record for the person entity using the document entity// provenance record is on the "name" field varpd=newKnowledgeGraphProvenanceDescription(personHandle,"name",docHandle,"","comments");edit_op.Create(pd);// execute - create all the entities and relationship rows _together_edit_op.Execute();});
Create a Document Record 1
varok=awaitQueuedTask.Run(()=>{using(varkg_for_doc=kgLayer.GetDatastore()){varedit_op=newEditOperation(){Name="Create Document Example",SelectNewFeatures=true};vardoc_entity_name=GetDocumentTypeName(kg_for_doc.GetDataModel());if(string.IsNullOrEmpty(doc_entity_name))returnfalse;varhasdoc_rel_name=GetHasDocumentTypeName(kg_for_doc.GetDataModel());if(string.IsNullOrEmpty(hasdoc_rel_name))returnfalse;//Document can also be FeatureClassvardoc_tbl=kg_for_doc.OpenDataset<Table>(doc_entity_name);vardoc_rel_tbl=kg_for_doc.OpenDataset<Table>(hasdoc_rel_name);//This is the document to be added...file, image, resource, etc.vardoc_url=@"E:\Data\Temp\HelloWorld.txt";vartext=System.IO.File.ReadAllText(url);//Set document propertiesvarattribs=newDictionary<string,object>();attribs["contentType"]=@"text/plain";attribs["name"]=System.IO.Path.GetFileName(url);attribs["url"]=doc_url;//Add geometry if relevant//attribs["Shape"] = doc_location;//optionalattribs["fileExtension"]=System.IO.Path.GetExtension(doc_url);attribs["text"]=System.IO.File.ReadAllText(doc_url);//optional and arbitrary - your choiceattribs["title"]=System.IO.Path.GetFileNameWithoutExtension(doc_url);attribs["keywords"]=@"text,file,example";attribs["metadata"]="";//Specify any additional custom attributes added to the document//schema by the user as needed....//attribs["custom_attrib"] = "Foo";//attribs["custom_attrib2"] = "Bar";//Get the entity whose document this is...varorg_fc=kg_for_doc.OpenDataset<FeatureClass>("Organization");varqf=newQueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};varorigin_org_id=Guid.Empty;using(varrc=org_fc.Search(qf)){if(!rc.MoveNext())returnfalse;origin_org_id=rc.Current.GetGlobalID();//For the relate}//Create the document row/featurevarrowtoken=edit_op.Create(doc_tbl,attribs);if(edit_op.Execute()){//Create the relationship rowattribs.Clear();//we need the names of the origin and destination relation propertiesvarkg_prop_info=kg_for_doc.GetPropertyNameInfo();//Specify the origin entity (i.e. the document 'owner') and//the document being related to (i.e. the document 'itself')attribs[kg_prop_info.OriginIDPropertyName]=origin_org_id;//entityattribs[kg_prop_info.DestinationIDPropertyName]=rowtoken.GlobalID;//document//Specify any custom attributes added to the has document//schema by the user as needed....//attribs["custom_attrib"] = "Foo";//attribs["custom_attrib2"] = "Bar";//"Chain" a second create for the relationship - this ensures that//Both creates (doc _and_ "has doc" relation) will be -undone- together if needed//....in other words they will behave as if they are a -single- transactionvaredit_op_rel=edit_op.CreateChainedOperation();edit_op_rel.Create(doc_rel_tbl,attribs);returnedit_op_rel.Execute();}returnfalse;}});}stringGetDocumentTypeName(KnowledgeGraphDataModelkg_dm){varentity_types=kg_dm.GetEntityTypes();foreach(varentity_typeinentity_types){varrole=entity_type.Value.GetRole();if(role==KnowledgeGraphNamedObjectTypeRole.Document)returnentity_type.Value.GetName();}return"";}stringGetHasDocumentTypeName(KnowledgeGraphDataModelkg_dm){varrel_types=kg_dm.GetRelationshipTypes();foreach(varrel_typeinrel_types){varrole=rel_type.Value.GetRole();if(role==KnowledgeGraphNamedObjectTypeRole.Document)returnrel_type.Value.GetName();}return"";
Create a Document Record 2
awaitQueuedTask.Run(()=>{using(varkg_for_doc=kgLayer.GetDatastore()){varpropInfo=kg_for_doc.GetPropertyNameInfo();if(!propInfo.SupportsDocuments)returnfalse;varedit_op=newEditOperation(){Name="Create Document Example",SelectNewFeatures=true};vardoc_entity_name=propInfo.DocumentTypeName;varhasdoc_rel_name=GetHasDocumentTypeName(kg.GetDataModel());//Document can also be FeatureClassvardoc_tbl=kg_for_doc.OpenDataset<Table>(doc_entity_name);vardoc_rel_tbl=kg_for_doc.OpenDataset<Table>(hasdoc_rel_name);//This is the document to be added...file, image, resource, etc.vardoc_url=@"E:\Data\Temp\HelloWorld.txt";// create the KnowledgeGraphDocumentDescriptionvarkgDocDesc=newKnowledgeGraphDocumentDescription(doc_url);// if there is a geometry use the following ctor// var kgDocDesc = new KnowledgeGraphDocumentDescription(doc_url, doc_location);// if you have additional custom attributes //var customDocAtts = new Dictionary<string, object>();//customDocAtts.Add("custom_attrib", "Foo");//customDocAtts.Add("custom_attrib2", "Bar");//var kgDocDesc = new KnowledgeGraphDocumentDescription(url, null, customDocAtts);// add additional properties if requiredkgDocDesc.Keywords=@"text,file,example";// The Create method will auto-populate the Url, Name, FileExtension and contentType fields of the document row// from the path supplied. varrowToken=edit_op.Create(doc_tbl,kgDocDesc);//Get the entity whose document this is...varorg_fc=kg_for_doc.OpenDataset<FeatureClass>("Organization");varqf=newQueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};varorigin_org_id=Guid.Empty;using(varrc=org_fc.Search(qf)){if(!rc.MoveNext())returnfalse;origin_org_id=rc.Current.GetGlobalID();//For the relate}// set up the row handlesvaroriginHandle=newRowHandle(org_fc,origin_org_id);// entityvardestinationHandle=newRowHandle(rowToken);// document// create the KnowledgeGraphRelationshipDescriptionvarrd=newKnowledgeGraphRelationshipDescription(originHandle,destinationHandle);// if you have additional custom attributes for the "HasDocument" relationship//var customHasDocAtts = new Dictionary<string, object>();//customHasDocAtts.Add("custom_attrib", "Foo");//customHasDocAtts.Add("custom_attrib2", "Bar");//var rd = new KnowledgeGraphRelationshipDescription(originHandle, destinationHandle, customHasDocAtts);// create the relate record using the same edit operationedit_op.Create(doc_rel_tbl,rd);//Call execute to create all the entities and relationship rows _together_returnedit_op.Execute();}});
Modify an Entity and Relationship record
varmv=MapView.Active;awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){Name="Modify an Entity and Relationship record",SelectModifiedFeatures=true};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer=mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//Entityvarorg_fl=kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer =>child_layer.Name=="Organization");//and/or Relationshipvarrel_stbl=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="HasEmployee");//Get the entity feature to modifylongorg_oid=-1;varorg_gid=Guid.Empty;varqf=newQueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};using(varrc=org_fl.Search(qf)){if(!rc.MoveNext())return;org_oid=rc.Current.GetObjectID();org_gid=rc.Current.GetGlobalID();}if(org_oid==-1)return;//nothing to modifyvarattribs=newDictionary<string,object>();//Specify attributes to be updatedattribs["Name"]="Acme Ltd.";attribs["Description"]="Specializes in household items";attribs["SHAPE"]=mv.Extent.Center;//Add to the edit operationedit_op.Modify(org_fl,org_oid,attribs);//Get the relationship record (if a relate is being updated)//we need the name of the origin id propertyvarkg_prop_info=kg.GetPropertyNameInfo();varsql=$"{kg_prop_info.OriginIDPropertyName} = ";sql+="'"+org_gid.ToString("B").ToUpper()+"'";qf=newQueryFilter(){WhereClause=sql,SubFields="*"};longrel_oid=-1;using(varrc=rel_stbl.Search(qf)){if(!rc.MoveNext())return;rel_oid=rc.Current.GetObjectID();}if(rel_oid>-1){//add the relate row updates to the edit operationattribs.Clear();//we are going to re-use the dictionaryattribs["StartDate"]=newDateTimeOffset(DateTime.Now);attribs["custom_attrib"]="Foo";attribs["custom_attrib2"]="Bar";//Add to the edit operationedit_op.Modify(rel_stbl,rel_oid,attribs);}//do the update(s)if(edit_op.Execute()){//TODO: Operation succeeded}});
Delete an Entity record
varmv=MapView.Active;awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){Name="Delete an Entity record"};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer=mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//Entityvarorg_fl=kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(child_layer =>child_layer.Name=="Organization");//Get the entity feature(s) to deletelongorg_oid=-1;varqf=newQueryFilter(){WhereClause="name = 'Acme'",SubFields="*"};using(varrc=org_fl.Search(qf)){if(!rc.MoveNext())return;//nothing to deleteorg_oid=rc.Current.GetObjectID();}edit_op.Delete(org_fl,org_oid);edit_op.Execute();//Do the delete});
Delete a Relationship record 1
varmv=MapView.Active;awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){Name="Delete a Relationship record"};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer=mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//Relationshipvarrel_stbl=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="HasEmployee");//Get the relation row to deletelongrel_oid=-1;using(varrc=rel_stbl.Search()){if(!rc.MoveNext())return;//arbitrarily, in this example, get the first rowrel_oid=rc.Current.GetObjectID();}edit_op.Delete(rel_stbl,rel_oid);edit_op.Execute();//Do the delete});
Delete a Relationship record 2
varmv=MapView.Active;awaitQueuedTask.Run(()=>{varedit_op=newEditOperation(){Name="Delete a Relationship record"};//We are going to use mapmembers in this example//we could equally use feature classes/tablesvarkg_layer=mv.Map.GetLayersAsFlattenedList()?.OfType<ArcGIS.Desktop.Mapping.KnowledgeGraphLayer>().First();//entitiesvarentityOrg=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="Organization");varentityPerson=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="Person");//Relationshipvarrel_stbl=kg_layer.GetStandaloneTablesAsFlattenedList().First(child_layer =>child_layer.Name=="HasEmployee");// get the origin, destination recordsGuidguidOrigin=Guid.Empty;GuidguidDestination=Guid.Empty;using(varrc=entityOrg.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidOrigin=rc.Current.GetGlobalID();}using(varrc=entityPerson.Search()){if(rc.MoveNext())//Use the KnowledgeGraphPropertyInfo to avoid hardcoding...guidDestination=rc.Current.GetGlobalID();}varrd=newKnowledgeGraphRelationshipDescription(guidOrigin,guidDestination);edit_op.Delete(rel_stbl,rd);edit_op.Execute();//Do the delete});
Schema Edits
Create Entity and Relationship Types with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){varentity_name="PhoneCall";varrelate_name="WhoCalledWho";//Entity Fieldsvardescs1=newList<KnowledgeGraphPropertyDescription>();descs1.Add(newKnowledgeGraphPropertyDescription("PhoneOwner",FieldType.String));descs1.Add(newKnowledgeGraphPropertyDescription("PhoneNumber",FieldType.String));descs1.Add(newKnowledgeGraphPropertyDescription("LocationID",FieldType.BigInteger));descs1.Add(newKnowledgeGraphPropertyDescription("DateAndTime",FieldType.Date));//Relate Fieldsvardescs2=newList<KnowledgeGraphPropertyDescription>();descs2.Add(newKnowledgeGraphPropertyDescription("Foo",FieldType.String));descs2.Add(newKnowledgeGraphPropertyDescription("Bar",FieldType.String));varincludeShape=true;//change to false to omit the shape columnvarhasZ=false;varhasM=false;KnowledgeGraphEntityTypeDescriptionentityDesc=null;KnowledgeGraphRelationshipTypeDescriptionrelateDesc=null;if(includeShape){varsr=kg.GetSpatialReference();varshp_desc=newShapeDescription(GeometryType.Point,sr){HasM=hasM,HasZ=hasZ};entityDesc=newKnowledgeGraphEntityTypeDescription(entity_name,descs1,shp_desc);relateDesc=newKnowledgeGraphRelationshipTypeDescription(relate_name,descs2,shp_desc);}else{entityDesc=newKnowledgeGraphEntityTypeDescription(entity_name,descs1);relateDesc=newKnowledgeGraphRelationshipTypeDescription(relate_name,descs2);}//Run the schema buildertry{SchemaBuildersb=new(kg);sb.Create(entityDesc);sb.Create(relateDesc);//Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'//to refresh the Pro UIif(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Entity/Relate Create error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Delete Entity and Relationship Types with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){varentity_name="PhoneCall";varrelate_name="WhoCalledWho";varentityDesc=newKnowledgeGraphEntityTypeDescription(entity_name);varrelateDesc=newKnowledgeGraphRelationshipTypeDescription(relate_name);//Run the schema buildertry{SchemaBuildersb=new(kg);sb.Delete(entityDesc);sb.Delete(relateDesc);//Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'//to refresh the Pro UIif(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Entity/Relate Delete error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Modify Entity and Relationship Type Schemas with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){varentity_name="PhoneCall";varrelate_name="WhoCalledWho";varkvp_entity=kg.GetDataModel().GetEntityTypes().First(r =>r.Key==entity_name);varkvp_relate=kg.GetDataModel().GetRelationshipTypes().First(r =>r.Key==relate_name);//Let's delete one field and add a new one from each//A field gets deleted implicitly if it is not included in the list of//fields - or "properties" in this case....so we will remove the last//property from the listvarentity_props=kvp_entity.Value.GetProperties().Reverse().Skip(1).Reverse();varprop_descs=newList<KnowledgeGraphPropertyDescription>();foreach(varpropinentity_props){if(prop.FieldType==FieldType.Geometry){continue;//skip shape}varprop_desc=newKnowledgeGraphPropertyDescription(prop);prop_descs.Add(prop_desc);}//deal with shape - we need to keep it//SchemaBuilder deletes any field not included in the "modify" listShapeDescriptionshape_desc=null;if(kvp_entity.Value.GetIsSpatial()){vargeom_def=kvp_entity.Value.GetShapeDefinition();varshape_name=kvp_entity.Value.GetShapeField();shape_desc=newShapeDescription(shape_name,geom_def.geometryType,geom_def.sr);}//add the new entity propertyprop_descs.Add(KnowledgeGraphPropertyDescription.CreateStringProperty("foo",10));//make a description for the entity type - ok if shape_desc is nullvarentityDesc=newKnowledgeGraphEntityTypeDescription(entity_name,prop_descs,shape_desc);//Add the entity type description to the schema builder using 'Modify'SchemaBuildersb=new(kg);sb.Modify(entityDesc);//Repeat for the relationship - assuming we have at least one custom attribute field//that can be deleted on our relationship schema...varrel_props=kvp_relate.Value.GetProperties().Reverse().Skip(1).Reverse();varrel_prop_descs=newList<KnowledgeGraphPropertyDescription>();foreach(varpropinrel_props){if(prop.FieldType==FieldType.Geometry){continue;//skip shape}varprop_desc=newKnowledgeGraphPropertyDescription(prop);rel_prop_descs.Add(prop_desc);}//deal with shape - we need to keep it//SchemaBuilder deletes any field not included in the "modify" listShapeDescriptionshape_desc_rel=null;if(kvp_relate.Value.GetIsSpatial()){vargeom_def=kvp_relate.Value.GetShapeDefinition();varshape_name=kvp_relate.Value.GetShapeField();shape_desc_rel=newShapeDescription(shape_name,geom_def.geometryType,geom_def.sr);}//add a new relationship propertyrel_prop_descs.Add(KnowledgeGraphPropertyDescription.CreateStringProperty("bar",10));//make a description for the relationship type - ok if shape_desc is nullvarrelDesc=newKnowledgeGraphRelationshipTypeDescription(relate_name,rel_prop_descs,shape_desc_rel);//Add the relationship type description to the schema builder using 'Modify'sb.Modify(relDesc);//Run the schema buildertry{//Use the KnowledgeGraph extension method 'ApplySchemaEdits(...)'//to refresh the Pro UIif(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Entity/Relate Modify error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Create Attribute Indexes on KG Schemas with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){varentity_name="PhoneCall";//indexes are managed on the GDB objects...varentity_table_def=kg.GetDefinition<TableDefinition>(entity_name);varentity_table_desc=newTableDescription(entity_table_def);varentity_table_flds=entity_table_def.GetFields();AttributeIndexDescriptionattr_index1=null;AttributeIndexDescriptionattr_index2=null;foreach(varfldinentity_table_flds){//index the first string fieldif(fld.FieldType==FieldType.String&&attr_index1==null){if(fld.Name=="ESRI__ID")//special casecontinue;//Index _must_ be ascending for KGattr_index1=newAttributeIndexDescription("Index1",entity_table_desc,newList<string>{fld.Name}){IsAscending=true};}//index the first numeric field (if there is one)if((fld.FieldType==FieldType.BigInteger||fld.FieldType==FieldType.Integer||fld.FieldType==FieldType.Single||fld.FieldType==FieldType.SmallInteger||fld.FieldType==FieldType.Double)&&attr_index2==null){attr_index2=newAttributeIndexDescription("Index2",entity_table_desc,newList<string>{fld.Name}){IsAscending=true,IsUnique=true//optional - unique if all values are to be unique in the index};}if(attr_index1!=null&&attr_index2!=null)break;}if(attr_index1==null&&attr_index2==null)return;//nothing to index//Run the schema buildertry{SchemaBuildersb=new(kg);if(attr_index1!=null)sb.Create(attr_index1);if(attr_index2!=null)sb.Create(attr_index2);if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Create index error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Delete Attribute Indexes on KG Schemas with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){varentity_name="PhoneCall";//indexes are managed on the GDB objects...varentity_table_def=kg.GetDefinition<TableDefinition>(entity_name);varentity_table_desc=newTableDescription(entity_table_def);varindexes=entity_table_def.GetIndexes();foreach(varidxinindexes){System.Diagnostics.Debug.WriteLine($"Index {idx.GetName()}");}varidx1=indexes.FirstOrDefault(
idx =>idx.GetName().ToLower()=="Index1".ToLower());varidx2=indexes.FirstOrDefault(
idx =>idx.GetName().ToLower()=="Index2".ToLower());if(idx1==null&&idx2==null)return;//Run the schema buildertry{SchemaBuildersb=new(kg);if(idx1!=null){varidx_attr=newAttributeIndexDescription(idx1,entity_table_desc);sb.Delete(idx_attr);}if(idx2!=null){varidx_attr=newAttributeIndexDescription(idx2,entity_table_desc);sb.Delete(idx_attr);}if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Delete index error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Create Domain and Field Definition on KG Schemas with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){varentity_name="Fruit";//Domains are managed on the GDB objects...varfruit_fc=kg.OpenDataset<FeatureClass>(entity_name);varfruit_fc_def=fruit_fc.GetDefinition();varfieldFruitTypes=fruit_fc_def.GetFields().FirstOrDefault(f =>f.Name=="FruitTypes");varfieldShelfLife=fruit_fc_def.GetFields().FirstOrDefault(f =>f.Name=="ShelfLife");//Create a coded value domain and add it to a new fieldvarfruit_cvd_desc=newCodedValueDomainDescription("FruitTypes",FieldType.String,newSortedList<object,string>{{"A","Apple"},{"B","Banana"},{"C","Coconut"}}){SplitPolicy=SplitPolicy.Duplicate,MergePolicy=MergePolicy.DefaultValue};//Create a Range Domain and add the domain to a new field description alsovarshelf_life_rd_desc=newRangeDomainDescription("ShelfLife",FieldType.Integer,0,14);varsb=newSchemaBuilder(kg);sb.Create(fruit_cvd_desc);sb.Create(shelf_life_rd_desc);//Create the new field descriptions that will be associated with the//"new" FruitTypes coded value domain and the ShelfLife range domainvarfruit_types_fld=newArcGIS.Core.Data.DDL.FieldDescription("FruitTypes",FieldType.String);fruit_types_fld.SetDomainDescription(fruit_cvd_desc);//ShelfLife will use the range domainvarshelf_life_fld=newArcGIS.Core.Data.DDL.FieldDescription("ShelfLife",FieldType.Integer);shelf_life_fld.SetDomainDescription(shelf_life_rd_desc);//Add the descriptions to the list of field descriptions for the//fruit feature class - Modify schema needs _all_ fields to be included//in the schema, not just the new ones to be added.varfruit_fc_desc=newFeatureClassDescription(fruit_fc_def);varmodified_fld_descs=newList<ArcGIS.Core.Data.DDL.FieldDescription>(fruit_fc_desc.FieldDescriptions);modified_fld_descs.Add(fruit_types_fld);modified_fld_descs.Add(shelf_life_fld);//Create a feature class description to modify the fruit entity//with the new fields and their associated domainsvarupdated_fruit_fc=newFeatureClassDescription(entity_name,modified_fld_descs,fruit_fc_desc.ShapeDescription);//Add the modified fruit fc desc to the schema buildersb.Modify(updated_fruit_fc);//Run the schema buildertry{if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Create domains error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});
Delete Domain on KG Schemas with SchemaBuilder
awaitQueuedTask.Run(()=>{using(varkg=GetKnowledgeGraph(url)){//Get all the domains in the KGvardomains=kg.GetDomains();varsb=newSchemaBuilder(kg);foreach(vardomainindomains){//skip the special provenance domainvarname=domain.GetName();if(string.Compare(name,"esri__provenanceSourceType",true)==0)continue;//skip this one//Delete all other domainsif(domainisRangeDomainrd)sb.Delete(newRangeDomainDescription(rd));elseif(domainisCodedValueDomaincvd)sb.Delete(newCodedValueDomainDescription(cvd));}try{//note: will throw an InvalidOperationException if there are no operations//to run. Will also delete associated fields dependent on deleted domain(s)if(!kg.ApplySchemaEdits(sb)){varerr_msg=string.Join(",",sb.ErrorMessages.ToArray());System.Diagnostics.Debug.WriteLine($"Delete domains error: {err_msg}");}}catch(Exceptionex){System.Diagnostics.Debug.WriteLine(ex.ToString());}}});}KnowledgeGraphGetKnowledgeGraph(stringurl){varkg_props=newKnowledgeGraphConnectionProperties(newUri(url));returnnewKnowledgeGraph(kg_props);
KnowledgeGraph Centrality
Compute Centrality Using Defaults
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ....) {//take default settings...//undirected relationship interpretation//use default relationship importance = 0//use default relationship cost = 0//use default Multiedge factor = 0//no normalizationvarkg_config=newCIMKnowledgeGraphCentralityConfiguration();//include all entities from the kg in the subgraph//(no filters)varkg_subgraph=newCIMKnowledgeGraphSubGraph();//include all centrality measuresCentralityMeasure[]measures=[CentralityMeasure.Degree,CentralityMeasure.InDegree,CentralityMeasure.OutDegree,CentralityMeasure.Coreness,//Coreness only wks w/ undirected relatesCentralityMeasure.Betweenness,CentralityMeasure.Closeness,CentralityMeasure.Harmonic,CentralityMeasure.Eigenvector,CentralityMeasure.PageRank];//compute centralityvarkg_centrality_results=kg.ComputeCentrality(kg_config,kg_subgraph,measures);//TODO - process results});
Process Centrality Results
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ....) {//use defaults...varkg_config=newCIMKnowledgeGraphCentralityConfiguration();//include all entities from the kg in the subgraph//(no filters)varkg_subgraph=newCIMKnowledgeGraphSubGraph();//include all centrality measuresCentralityMeasure[]measures=[CentralityMeasure.Degree,CentralityMeasure.InDegree,CentralityMeasure.OutDegree,CentralityMeasure.Coreness,CentralityMeasure.Betweenness,CentralityMeasure.Closeness,CentralityMeasure.Harmonic,CentralityMeasure.Eigenvector,CentralityMeasure.PageRank];//compute centralityvarkg_centrality_results=kg.ComputeCentrality(kg_config,kg_subgraph,measures);//output results - results include measure scores for all entities//in all types in the subgraphSystem.Diagnostics.Debug.WriteLine("Centrality Results:");foreach(varnamed_typeinkg_centrality_results.NamedTypes){System.Diagnostics.Debug.WriteLine($"Named type: {named_type}");foreach(varuidinkg_centrality_results.GetUidsForNamedType(named_type)){//measure scores include one score per measure in the input measures arrayvarscores=kg_centrality_results.Scores[uid];StringBuildersb=newStringBuilder();varsep="";//or use kg_centrality_results.Scores.Measures.Length//kg_centrality_results.Scores.Measures is there for conveniencefor(intm=0;m<measures.Length;m++){sb.Append($"{sep}{measures[m].ToString()}: {scores[m]}");sep=", ";}System.Diagnostics.Debug.WriteLine($" '{uid}' {sb.ToString()}");}}});
Configure Centrality
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ....) {//configure centrality with custom settingsvarkg_config=newCIMKnowledgeGraphCentralityConfiguration(){RelationshipsInterpretation=CentralityRelationshipInterpretation.Directed,MultiedgeFactor=1.0,//cumulative importanceNormalization=CentralityScoresNormalization.None,DefaultRelationshipCost=1.0,DefaultRelationshipImportance=1.0,RelationshipCostProperty=string.Empty,RelationshipImportanceProperty=string.Empty};//include all entities from the kg in the subgraph//(no filters)varkg_subgraph=newCIMKnowledgeGraphSubGraph();//include the relevant centrality measuresCentralityMeasure[]measures=[CentralityMeasure.Degree,CentralityMeasure.InDegree,CentralityMeasure.OutDegree,CentralityMeasure.Betweenness,CentralityMeasure.Closeness,CentralityMeasure.Harmonic,CentralityMeasure.Eigenvector,CentralityMeasure.PageRank];//Note: CentralityMeasure.Coreness cannot be calculated//with directed relationships, so it is not included here.//Specfying Coreness (with directed or reveresed relationships) will//throw an exception//compute centralityvarkg_centrality_results=kg.ComputeCentrality(kg_config,kg_subgraph,measures);//TODO process results});
Configure Centrality Entity SubGraph Filters
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ....) {//Assume KG contains Entity NamedTypes "A","B","C", and "D"////We can use either of a CIMKnowledgeGraphNamedTypeFilterByInstances//or CIMKnowledgeGraphNamedTypeFilterByType to filter instances for//_including_ in or _excluding_ from entities and relates wrt the subgraph.////Use CIMKnowledgeGraphNamedTypeFilterByInstances to filter by instance id//Use CIMKnowledgeGraphNamedTypeFilterByType to filter by type name and with//an optional property filter predicate to filter by property value(s)//Example 1.//Include all entities (and relates) from the kg in the subgraph//Leave kg_subgraph.EntityFilters null.//(kg_subgraph.RelationshipFilters is also null)//The collection of Entity and Relate filters are both empty//Everything is includedvarkg_subgraph=newCIMKnowledgeGraphSubGraph();//Example 2//Include a set of Entities from A (all of B, C, D will be implicitly excluded)varkg_filter2=newCIMKnowledgeGraphNamedTypeFilterByInstances(){FilterType=KGFilterType.Include,NamedType="A",InstancesIDs=list_of_ids.ToArray()//list_of_ids contains desired uids for "A"//note: -if list_of_ids is empty then -no-//instances of A will be included.};varentity_filters2=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters2.Add(kg_filter2);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters2.ToArray();//Example 3//Exclude a set of Entities from A (all of B, C, D will be implicitly included)varkg_filter3=newCIMKnowledgeGraphNamedTypeFilterByInstances(){FilterType=KGFilterType.Exclude,NamedType="A",InstancesIDs=list_of_ids.ToArray()//list_of_ids contains desired uids for "A"//note: -if list_of_ids is empty then -no-//instances of A will be excluded.};varentity_filters3=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters3.Add(kg_filter3);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters3.ToArray();//Example 4//Include all Entities from A via named type (all of B, C, D//will be implicitly excluded)varkg_filter4=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Include,NamedType="A"//all of A will be included//predicate is empty};varentity_filters4=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters4.Add(kg_filter4);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters4.ToArray();//Example 5//Exclude all Entities from A via named type (all of B, C, D//will be implicitly included)varkg_filter5=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Exclude,NamedType="A"//all of A will be excluded//predicate is empty};varentity_filters5=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters5.Add(kg_filter5);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters5.ToArray();//Example 6//Include all entities from B and C and//a subset from D via a set of ids (A is implicitly excluded)varkg_filter6_b=newCIMKnowledgeGraphNamedTypeFilterByType();varkg_filter6_c=newCIMKnowledgeGraphNamedTypeFilterByType();kg_filter6_b.NamedType="B";//Include is default, predicate is emptykg_filter6_c.NamedType="C";//Include is default, predicate is empty//TODO... populate list with uids from "D"...varkg_filter6_d=newCIMKnowledgeGraphNamedTypeFilterByInstances();kg_filter6_d.NamedType="D";//Include is defaultkg_filter6_d.InstancesIDs=list_of_ids.ToArray();varentity_filters6=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters6.Add(kg_filter6_b);//order doesn't matterentity_filters6.Add(kg_filter6_c);entity_filters6.Add(kg_filter6_d);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters6.ToArray();//Example 7//Exclude all entities from B and C and//a subset from D (A is implicitly included)varkg_filter7_b=newCIMKnowledgeGraphNamedTypeFilterByType();varkg_filter7_c=newCIMKnowledgeGraphNamedTypeFilterByType();kg_filter7_b.NamedType="B";//predicate is emptykg_filter7_c.NamedType="C";//predicate is emptykg_filter7_b.FilterType=KGFilterType.Exclude;kg_filter7_c.FilterType=KGFilterType.Exclude;varkg_filter7_d=newCIMKnowledgeGraphNamedTypeFilterByInstances();kg_filter7_d.NamedType="D";kg_filter7_d.FilterType=KGFilterType.Exclude;kg_filter7_d.InstancesIDs=list_of_ids.ToArray();//ids to be excludedvarentity_filters7=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters7.Add(kg_filter7_b);//order doesn't matterentity_filters7.Add(kg_filter7_c);entity_filters7.Add(kg_filter7_d);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters7.ToArray();//Example 8//Include a subset of Entities from A using a property//filter predicate (all of B, C, D will be implicitly excluded)//we -must- use a predicate prefix in our expression//select instances of A w/ Material = 'Steel'varexpr8=$"a.Material = 'Steel'";//prefix can be anything - foo, bar, fred, etc.varkg_filter8=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="A",//Include is defaultPropertyFilterPredicate=expr8//include ids w/Material='Steel'};varentity_filters8=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters8.Add(kg_filter8);//note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters8.ToArray();//Example 9//Exclude a subset of Entities from A using a property//filter predicate (all of B, C, D will be implicitly included)//we -must- use a predicate prefix in our expression//select instances of A with Material <> 'Steel'varexpr9=$"a.Material <> 'Steel'";//prefix can be anything - foo, bar, fred, etc.varkg_filter9=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Exclude,NamedType="A",PropertyFilterPredicate=expr9//exclude ids w/Material <> 'Steel'};varentity_filters9=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters9.Add(kg_filter9);//Note: All relates are included as no RelationshipFilters are specified//var kg_subgraph = ...kg_subgraph.EntityFilters=entity_filters9.ToArray();});
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ...) {//Assume Relationship NamedTypes "R1","R2",and "R3"////We can use either of a CIMKnowledgeGraphNamedTypeFilterByInstances//or CIMKnowledgeGraphNamedTypeFilterByType to filter instances for//_including_ in or _excluding_ from entities and relates wrt the subgraph.////Use CIMKnowledgeGraphNamedTypeFilterByInstances to filter by instance id//Use CIMKnowledgeGraphNamedTypeFilterByType to filter by type name and with//an optional property filter predicate to filter by property value(s)//Example 1.//Include all relates (and entities) from the kg in the subgraph//Leave kg_subgraph.RelationshipFilters null//(kg_subgraph.EntityFilters is also null)//The collection of Entity and Relate filters are both empty//Everything is includedvarkg_subgraph=newCIMKnowledgeGraphSubGraph();//note - relates can only be included if their corresponding entity end points//are also included in the subgraph.//Example 2//Include a set of Relates from R1 (all of R2, R3 will be implicitly excluded)varkg_filter_r2=newCIMKnowledgeGraphNamedTypeFilterByInstances(){FilterType=KGFilterType.Include,NamedType="R1",InstancesIDs=list_of_ids.ToArray()//list_of_ids contains desired uids for "R1"//note: -if list_of_ids is empty then -no-//instances of R1 will be included.};//var kg_subgraph = ...varrelate_filters2=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters2.Add(kg_filter_r2);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters2.ToArray();//Example 3//Exclude a set of Relates from R1 (all of R2, R3 will be implicitly included)varkg_filter_r3=newCIMKnowledgeGraphNamedTypeFilterByInstances(){FilterType=KGFilterType.Exclude,NamedType="R1",InstancesIDs=list_of_ids.ToArray()//list_of_ids contains desired uids for "R1"//note: -if list_of_ids is empty then -no-//instances of R1 will be excluded.};varrelate_filters3=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters3.Add(kg_filter_r3);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters3.ToArray();//Example 4//Include all Relates from R1 via named type (all of R2, R3//will be implicitly excluded)varkg_filter_r4=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Include,NamedType="R1",//all of R1 will be included//predicate is empty};varrelate_filters4=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters4.Add(kg_filter_r4);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters4.ToArray();//Example 5//Exclude all Relates from R1 via named type (all of R2, R3//will be implicitly included)varkg_filter_r5=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Exclude,NamedType="R1"//all of R1 will be excluded};varrelate_filters5=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters5.Add(kg_filter_r5);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters5.ToArray();//Example 6//Include all relates from R2 and//a subset from R3 (R1 is implicitly excluded)varkg_filter_r6_r2=newCIMKnowledgeGraphNamedTypeFilterByType();kg_filter_r6_r2.NamedType="R2";//Include is default, predicate is empty//TODO... populate list with uids from "R3"...varkg_filter_r6_r3=newCIMKnowledgeGraphNamedTypeFilterByInstances();kg_filter_r6_r3.NamedType="R3";//Include is defaultkg_filter_r6_r3.InstancesIDs=list_of_ids.ToArray();varrelate_filters6=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters6.Add(kg_filter_r6_r2);//order doesn't matterrelate_filters6.Add(kg_filter_r6_r3);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters6.ToArray();//Example 7//Exclude all relates from R2 and//a subset from R3 (R1 is implicitly included)varkg_filter_r7_r2=newCIMKnowledgeGraphNamedTypeFilterByType();kg_filter_r7_r2.NamedType="R2";kg_filter_r7_r2.FilterType=KGFilterType.Exclude;//TODO... populate list with uids from "R3"...varkg_filter_r7_r3=newCIMKnowledgeGraphNamedTypeFilterByInstances();kg_filter_r7_r3.NamedType="R3";kg_filter_r7_r3.FilterType=KGFilterType.Exclude;kg_filter_r7_r3.InstancesIDs=list_of_ids.ToArray();varrelate_filters7=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters7.Add(kg_filter_r7_r2);//order doesn't matterrelate_filters7.Add(kg_filter_r7_r3);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters6.ToArray();//Example 8//Include a subset of Relates from R1 using a property//filter predicate (all of R2, R3 will be implicitly excluded)//we -must- use a predicate prefix in our expression//select instances of R1 w/Distance = 2000varexpr8=$"r1.Distance = 2000";//prefix can be anything - foo, bar, fred, etc.varkg_filter_r8=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="R1",//Include is defaultPropertyFilterPredicate=expr8};varrelate_filters8=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters8.Add(kg_filter_r8);//note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters8.ToArray();//Example 9//Exclude a subset of Relates from R1 using a property//filter predicate (all of R2, R3 will be implicitly included)//we -must- use a predicate prefix in our expression//select instances of R1 w/ Distance <> 2000varexpr9=$"r1.Distance <> 2000";//prefix can be anything - foo, bar, fred, etc.varkg_filter_r9=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Exclude,NamedType="R1",PropertyFilterPredicate=expr9//exclude ids w/ Distance <> 2000};varrelate_filters9=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters9.Add(kg_filter_r9);//Note: All entities are included as no EntityFilters are specified//var kg_subgraph = ...kg_subgraph.RelationshipFilters=relate_filters9.ToArray();});
Combine Centrality Entity and Relationship SubGraph Filters
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ...) {//Assume Entity NamedTypes "A","B","C", and "D"//Assume Relationship NamedTypes "R1","R2",and "R3"//Example 1//Include all Entities from A and B//Include all Relates from R1 and R2//(all of C, D, and R3 will be implicitly excluded)varkg_filter1_a=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Include,//defaultNamedType="A"};varkg_filter1_b=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Include,//defaultNamedType="B"};varkg_filter1_r1=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Include,//defaultNamedType="R1"};varkg_filter1_r2=newCIMKnowledgeGraphNamedTypeFilterByType(){FilterType=KGFilterType.Include,//defaultNamedType="R2"};varentity_filters1=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters1.Add(kg_filter1_a);entity_filters1.Add(kg_filter1_b);varrelate_filters1=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters1.Add(kg_filter1_r1);relate_filters1.Add(kg_filter1_r2);//var kgSubgraph = ...kgSubgraph.EntityFilters=entity_filters1.ToArray();kgSubgraph.RelationshipFilters=relate_filters1.ToArray();//Example 2 - //Include a subset of Entities from A using a predicate,//and all of B, C, D and all of R1 and R3 (but not R2)varprefix2="a";//prefix can be anything - foo, bar, fred, etc.varexpr2=$"{prefix2}.Material = 'Steel' AND "+$"{prefix2}.Role = 'Tier1'";varkg_filter2_a=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="A",//Include is defaultPropertyFilterPredicate=expr2};varkg_filter2_b=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="B"//Include is default};varkg_filter2_c=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="C"//Include is default};varkg_filter2_d=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="D"//Include is default};varkg_filter2_r1=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="R1"//Include is default};varkg_filter2_r3=newCIMKnowledgeGraphNamedTypeFilterByType(){NamedType="R3"//Include is default};varentity_filters2=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters2.Add(kg_filter2_a);entity_filters2.Add(kg_filter2_b);entity_filters2.Add(kg_filter2_c);entity_filters2.Add(kg_filter2_d);varrelate_filters2=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters2.Add(kg_filter2_r1);relate_filters2.Add(kg_filter2_r3);//var kgSubgraph = ...kgSubgraph.EntityFilters=entity_filters2.ToArray();kgSubgraph.RelationshipFilters=relate_filters2.ToArray();//Example 3//Exclude all entities from B and C and//a subset from D (A is implicitly included)////Include all relates from R2 and//a subset from R3 (R1 is implicitly excluded)varkg_filter3_b=newCIMKnowledgeGraphNamedTypeFilterByType();varkg_filter3_c=newCIMKnowledgeGraphNamedTypeFilterByType();kg_filter3_b.NamedType="B";kg_filter3_c.NamedType="C";kg_filter3_b.FilterType=KGFilterType.Exclude;kg_filter3_c.FilterType=KGFilterType.Exclude;//TODO... populate list with uids from "D"...varkg_filter3_d=newCIMKnowledgeGraphNamedTypeFilterByInstances();kg_filter3_d.NamedType="D";kg_filter3_d.FilterType=KGFilterType.Exclude;kg_filter3_d.InstancesIDs=list_of_ids.ToArray();varkg_filter3_r2=newCIMKnowledgeGraphNamedTypeFilterByType();kg_filter3_r2.NamedType="R2";//Include is default//TODO... populate list with uids from "R3"...varkg_filter3_r3=newCIMKnowledgeGraphNamedTypeFilterByInstances();kg_filter3_r3.NamedType="R3";//Include is defaultkg_filter3_r3.InstancesIDs=list_of_ids2.ToArray();varentity_filters3=newList<CIMKnowledgeGraphNamedTypeFilter>();entity_filters3.Add(kg_filter3_b);//order doesn't matterentity_filters3.Add(kg_filter3_c);entity_filters3.Add(kg_filter3_d);varrelate_filters3=newList<CIMKnowledgeGraphNamedTypeFilter>();relate_filters3.Add(kg_filter3_r2);//order doesn't matterrelate_filters3.Add(kg_filter3_r3);//var kgSubgraph = ...kgSubgraph.EntityFilters=entity_filters3.ToArray();kgSubgraph.RelationshipFilters=relate_filters3.ToArray();});
Output Centrality Results
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{///var kgConfig = ...;//var kgSubgraph = ...;//var measures = ...;//using(var kg = ...) {varresults=kg.ComputeCentrality(kgConfig,kgSubgraph,measures);//loop through each (entity) named type (relates are never included in results)foreach(varnamed_typeinresults.NamedTypes){//Get the entity uids for each named typeforeach(varuidinresults.GetUidsForNamedType(named_type)){//Get the scores for each uid via the [] indexer on "Scores"varscores=results.Scores[uid];//There is one score per measure in the input measures array//Note: results.Scores.Measures is also provided for convenience...//for (int m = 0; m < results.Scores.Measures.Length; m++)for(intm=0;m<measures.Length;m++){varscore=scores[m];//score for the given measure//TODO - use measure score}}}});
Get Max and Min Centrality Result Scores No Sort or LINQ
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ...) {//var kgResults = kg.ComputeCentrality(...);varcount_entities=kgResults.RawUids.Count();varscore_len=kgResults.Scores.RawScores.Length;//Find the max and min score for each measure w/out//using LINQ or sortingfor(intm=0;m<kgResults.Scores.Measures.Length;m++){//index into the scores array for the current measurevarstart_idx=count_entities*m;varend_idx=start_idx+count_entities;doublemax_score=double.MinValue;doublemin_score=double.MaxValue;List<object>max_uids=newList<object>();List<object>min_uids=newList<object>();for(inti=0,s=start_idx;s<end_idx;i++,s++){varscore=kgResults.Scores.RawScores[s];//maxif(score>max_score){max_score=score;max_uids.Clear();max_uids.Add(kgResults.RawUids[i]);}elseif(score==max_score){//Collect all uids with the max scoremax_uids.Add(kgResults.RawUids[i]);}//minif(score<min_score){min_score=score;min_uids.Clear();min_uids.Add(kgResults.RawUids[i]);}elseif(score==min_score){//Collect all uids with the min scoremin_uids.Add(kgResults.RawUids[i]);}}//TODO - use the max and min scores and uids for//the current measure "measures[m]"//max_score, max_uids//min_score, min_uids}});
Get Max and Min Centrality Result Scores With Sort and Linq
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{//using(var kg = ...) {//var kgResults = kg.ComputeCentrality(...);varcount_entities=kgResults.RawUids.Count();varscore_len=kgResults.Scores.RawScores.Length;//Find the max and min score for each measure using LINQfor(intm=0;m<kgResults.Scores.Measures.Length;m++){//index into the scores array for the current measurevarstart_idx=count_entities*m;varend_idx=start_idx+count_entities;//Get the scores for the specified measurevarscores=Enumerable.Range(start_idx,count_entities).Select(i =>kgResults.Scores.RawScores[i]).ToArray();//max + minvarmax_score=scores.Max();varmin_score=scores.Min();//uids with the max scorevarmax_uids=Enumerable.Range(0,count_entities).Where(i =>scores[i]==max_score).Select(i =>kgResults.RawUids[i]).ToList();//uids with the min scorevarmin_uids=Enumerable.Range(0,count_entities).Where(i =>scores[i]==min_score).Select(i =>kgResults.RawUids[i]).ToList();//TODO - use the max and min scores and uids for//the current measure "measures[m]"//max_score, max_uids//min_score, min_uids}});
Get Top or Bottom N Centrality Result Scores
//using ArcGIS.Core.Data.Knowledge.Extensions;//Note: logic uses the following custom class:////public class KG_Score_Value {// public KG_Score_Value(double score, int uid_idx) {// Score = score;// Uid_idx = uid_idx;// }//// public double Score { get; set; }// public int Uid_idx { get; set; }//}//var kgResults = kg.ComputeCentrality(...);varcount_entities=kgResults.RawUids.Count();varscore_len=kgResults.Scores.RawScores.Length;intn=100;//Find the top and bottom "n" scores for each measurefor(intm=0;m<kgResults.Scores.Measures.Length;m++){//index into the scores array for the current measurevarstart_idx=count_entities*m;varend_idx=start_idx+count_entities;//Get the scores for the specified measurevarscores=Enumerable.Range(start_idx,count_entities).Select(i =>kgResults.Scores.RawScores[i]).ToArray();//use "KG_Score_Value" to hold the score and uid indexvaruid_idx=0;varkg_score_vals=Enumerable.Range(start_idx,count_entities).Select(i =>newKG_Score_Value(kgResults.Scores.RawScores[i],uid_idx++)).OrderByDescending(k =>k.Score).ToArray();//get up to the top or bottom N scoresif(n>kg_score_vals.Length)n=kg_score_vals.Length;//get the top N scores and uids - largest firstvartop_n=kg_score_vals.Take(n).ToList();//get the bottom N scores and uids - smallest firstvarbottom_n=kg_score_vals.TakeLast(n).Reverse().ToList();foreach(varkg_scoreintop_n){//TODO - use top "n" scoresvarscore=kg_score.Score;varuid1=kgResults.RawUids[kg_score.Uid_idx];//...use it}foreach(varkg_scoreinbottom_n){//TODO - use bottom "n" scoresvarscore=kg_score.Score;varuid1=kgResults.RawUids[kg_score.Uid_idx];//...use it}}
Get The NamedType for a Given UID in Result Scores
//object uid = "{.... uid value ....}";//or//object uid = kgResults.RawUids[i]; e.g. in/from a loopvarnamed_type="";foreach(varntinkgResults.NamedTypes){varuids=kgResults.GetUidsForNamedType(nt);if(uids.Contains(uid)){named_type=nt;//found itbreak;}}if(string.IsNullOrEmpty(named_type)){//uid not found in any named type//TODO - handle this case}//TODO - use the named type for the uid
KnowledgeGraph FFP
Run FFP Using Defaults
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Run FFP Using Defaults";//Origin EntitiesvaroriginEntities=newList<CIMFilteredFindPathsEntity>();varpoi_entity=newCIMFilteredFindPathsEntity();poi_entity.EntityTypeName="POI";//All entities of entity type "POI"poi_entity.PropertyFilterPredicate="";originEntities.Add(poi_entity);//Add the CIMFilteredFindPathsEntity to the OriginEntities collectionffp_config.OriginEntities=originEntities.ToArray();//Destination EntitiesvardestEntities=newList<CIMFilteredFindPathsEntity>();varsupp_entity=newCIMFilteredFindPathsEntity();supp_entity.EntityTypeName="Supplier";//All entities of entity type "Supplier"supp_entity.PropertyFilterPredicate="";destEntities.Add(supp_entity);//Add the CIMFilteredFindPathsEntity to the DestinationEntities collectionffp_config.DestinationEntities=destEntities.ToArray();//Path Filtersffp_config.PathFilters=[];//Empty//Traversalffp_config.TraversalDirections=[];//Empty//Otherffp_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 pathffp_config.MaxPathLength=(int)8;//Max number of relationships in pathffp_config.MaxCountPaths=(int)100000;//Total number of paths to returnffp_config.ClosedPathPolicy=KGClosedPathPolicy.Forbid;ffp_config.TimeFilter=null;varresults=kg.RunFilteredFindPaths(ffp_config);//TODO process/analyze results});
Run FFP Using Multiple Entities and Destinations
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Run FFP w Multiple Entities and Destinations";//Origin EntitiesvaroriginEntities=newList<CIMFilteredFindPathsEntity>();foreach(varentity_nameinnewList<string>{"Person","POI","Supplier","Plant"}){varorigin_entity=newCIMFilteredFindPathsEntity();origin_entity.EntityTypeName=entity_name;origin_entity.PropertyFilterPredicate="";originEntities.Add(origin_entity);}//Add the CIMFilteredFindPathsEntity to the OriginEntities collectionffp_config.OriginEntities=originEntities.ToArray();//Destination EntitiesvardestEntities=newList<CIMFilteredFindPathsEntity>();foreach(varentity_nameinnewList<string>{"Supplier","Plant","Part","Customer"}){vardest_entity=newCIMFilteredFindPathsEntity();dest_entity.EntityTypeName=entity_name;dest_entity.PropertyFilterPredicate="";destEntities.Add(dest_entity);}//Add the CIMFilteredFindPathsEntity to the DestinationEntities collectionffp_config.DestinationEntities=destEntities.ToArray();//Path Filtersffp_config.PathFilters=[];//Empty//Traversalffp_config.TraversalDirections=[];//Empty//Otherffp_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 pathffp_config.MaxPathLength=(int)8;//Max number of relationships in pathffp_config.MaxCountPaths=(int)100000;//Total number of paths to returnffp_config.ClosedPathPolicy=KGClosedPathPolicy.Forbid;ffp_config.TimeFilter=null;varresults=kg.RunFilteredFindPaths(ffp_config);//TODO process/analyze results});
Run FFP Using Specific Entities and Destinations by ID
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Run FFP w Specific Entities and Destinations";//Origin EntitiesvaroriginEntities=newList<CIMFilteredFindPathsEntity>();varorigin_entity=newCIMFilteredFindPathsEntity();origin_entity.EntityTypeName="POI";origin_entity.ID="{EC2A2D91-B09C-4CF6-93A3-51D6527CF51E}";//upper case guidorigin_entity.PropertyFilterPredicate="";//IgnoredoriginEntities.Add(origin_entity);varorigin_entity2=newCIMFilteredFindPathsEntity();origin_entity2.EntityTypeName="POI";origin_entity2.ID="{5008792F-3C67-4FCA-B1E9-756D6E389FDD}";//upper case guidorigin_entity2.PropertyFilterPredicate="";//IgnoredoriginEntities.Add(origin_entity2);//etc.//Add the CIMFilteredFindPathsEntity to the OriginEntities collectionffp_config.OriginEntities=originEntities.ToArray();//Destination Entities//Same thing, add specific entities using their UidsvardestEntities=newList<CIMFilteredFindPathsEntity>();vardest_entity=newCIMFilteredFindPathsEntity();dest_entity.EntityTypeName="Supplier";dest_entity.ID="{A3F5C2E1-8D3B-4E2A-9F4B-1C2D3E4F5A6B}";//upper case guiddest_entity.PropertyFilterPredicate="";destEntities.Add(dest_entity);vardest_entity2=newCIMFilteredFindPathsEntity();dest_entity2.EntityTypeName="Supplier";dest_entity2.ID="{B1C2D3E4-F5A6-7B8C-9D0E-1F2A3B4C5D6E}";//upper case guiddest_entity2.PropertyFilterPredicate="";destEntities.Add(dest_entity2);//etc.//Add the CIMFilteredFindPathsEntity to the OriginEntities collectionffp_config.DestinationEntities=destEntities.ToArray();//TODO - use the config//var results = kg.RunFilteredFindPaths(ffp_config);// ...});
Run FFP Using PropertyFilterPredicates
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Run FFP w PropertyFilterPredicates";//Origin EntitiesvaroriginEntities=newList<CIMFilteredFindPathsEntity>();varorigin_entity=newCIMFilteredFindPathsEntity();origin_entity.EntityTypeName="POI";//prefix can be anything - foo, bar, fred, n, x, etc.origin_entity.PropertyFilterPredicate="n.name = 'Robert Johnston'";originEntities.Add(origin_entity);varorigin_entity2=newCIMFilteredFindPathsEntity();origin_entity2.EntityTypeName="EnergySource";//prefix can be anything - foo, bar, fred, n, x, s, etc.origin_entity2.PropertyFilterPredicate="s.Source_Name = 'natural gas'";originEntities.Add(origin_entity2);//etc.//Add the CIMFilteredFindPathsEntity to the OriginEntities collectionffp_config.OriginEntities=originEntities.ToArray();//Destination Entities//Same thing, add specific entities using a PropertyFilterPredicate as neededvardestEntities=newList<CIMFilteredFindPathsEntity>();vardest_entity=newCIMFilteredFindPathsEntity();dest_entity.EntityTypeName="Supplier";//prefix can be anything - foo, bar, fred, n, x, s, etc.origin_entity.PropertyFilterPredicate="x.Supplier_Name = 'Supplier 84'";destEntities.Add(dest_entity);//etc.//Add the CIMFilteredFindPathsEntity to the OriginEntities collectionffp_config.DestinationEntities=destEntities.ToArray();//TODO - use the config//var results = kg.RunFilteredFindPaths(ffp_config);// ...});
Run FFP Using Path Filters
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Run FFP w Path Filters";//set origin entities//set destination entities//set path filtersvarpathFilters=newList<CIMFilteredFindPathsPathFilter>();varpath_filter=newCIMFilteredFindPathsPathFilter();path_filter.ItemTypeName="POI";path_filter.ItemType=KGPathFilterItemType.Entity;//To select specific entities, set the ID property or provide a filter predicate//path_filter.ID = "{B1C2D3E4-F5A6-7B8C-9D0E-1F2A3B4C5D6E}";//set a specific id//...or...use a predicate//path_filter.PropertyFilterPredicate = "n.name = 'Robert Johnston'";//Use IncludeOnly to only consider entities of this type in the pathpath_filter.FilterType=KGPathFilterType.IncludeOnly;//Use Exclude to ignore paths that contain excluded typespath_filter.FilterType=KGPathFilterType.Exclude;//Use MandatoryWaypoint if you have specific entities/entity types through//which all paths must pass through at least one entity of this typepath_filter.FilterType=KGPathFilterType.MandatoryWaypoint;//Use OptionalWaypoint if you have specific entities/entity types through//which all paths must pass through at least one entity from any of the//optional waypointspath_filter.FilterType=KGPathFilterType.OptionalWaypoint;//Add the path filter(s) to the collectionpathFilters.Add(path_filter);//Add more filters as needed//"Person", "Supplier", "Plant", etc.//Path Filtersffp_config.PathFilters=pathFilters.ToArray();//TODO - use the config//var results = kg.RunFilteredFindPaths(ffp_config);// ...});
Run FFP Using Traversal Filters
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Run FFP w Traversal Filters";//set origin entities//set destination entities//set any path filters//Set traversal filters//A traversal filter is used to specify the traversal direction of a relationship (to be)//included in the result paths. By default, paths are evaluated without considering the//direction of relationships in the graph - i.e. KGTraversalDirectionType.Any.//Relationships can be evaluated in specific directions by changing the KGTraversalDirectionType//enum value of the traversal_filter.TraversalDirectionType.//For example, the traversal direction is being set for the following relationship types...vartraversalFilters=newList<CIMKGTraversalDirection>();foreach(varrelationinnewList<string>{"near_poi","near_facility","near_facility2"}){vartraversal_filter=newCIMKGTraversalDirection();traversal_filter.RelationshipTypeName=relation;//All relationships of the specified type are considered (default)traversal_filter.TraversalDirectionType=KGTraversalDirectionType.Any;//Relationship can only be traversed from origin to destinationtraversal_filter.TraversalDirectionType=KGTraversalDirectionType.Forward;//Relationship can only be traversed from destination to origintraversal_filter.TraversalDirectionType=KGTraversalDirectionType.Backward;traversalFilters.Add(traversal_filter);}ffp_config.TraversalDirections=traversalFilters.ToArray();//etc.//TODO - use the config//var results = kg.RunFilteredFindPaths(ffp_config);// ...});
Create Link Chart from FFP Results
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(async()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Create Link Chart from FFP Results";//set up config//...varresults=kg.RunFilteredFindPaths(ffp_config);varpathsEntitiesAndRelationships=results.ExtractPathsEntitiesAndRelationships(null);//Create a KG layer id setvarkgLayerIdSet=KnowledgeGraphLayerIDSet.FromKnowledgeGraphIDSet(pathsEntitiesAndRelationships.ToKnowledgeGraphIDSet(KGResultContentFromFFP.EntitiesAndRelationships));//Create a brand new link chart with the results and show itvarlinkChart=MapFactory.Instance.CreateLinkChart("KG Intro",kg,kgLayerIdSet);varmapPane=awaitFrameworkApplication.Panes.CreateMapPaneAsync(linkChart);varlinkChartView=mapPane.MapView;//Change layout algo to match the default used by the UI after FFPawaitlinkChartView.SetLinkChartLayoutAsync(KnowledgeLinkChartLayoutAlgorithm.Hierarchical_TopToBottom);//Set root nodes - they correspond to the origin nodes of the result pathsvarkgLayerIdSetForRootNodes=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...varkg_layer=linkChart.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().First();varmapMembers=kg_layer.GetMapMembersAsFlattenedList();varoidDict=kgLayerIdSetForRootNodes.ToOIDDictionary();varmmDict=newDictionary<MapMember,List<long>>();foreach(varkvpinoidDict){varnamed_type=kvp.Key;foreach(varmminmapMembers){if(mmisLinkChartFeatureLayerfl_lc&&fl_lc.IsEntity){if(fl_lc.GetTypeName().ToLower()==named_type.ToLower()){varlc_oids=newList<long>();//these oids are from the geodatabasevaroid_field=$"{fl_lc.GetTypeName()}.objectid";varid_list=string.Join(',',kvp.Value.ToArray());varwhere=$"{fl_lc.GetTypeName()}.objectid IN ({id_list})";varqf=newArcGIS.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};varrc=fl_lc.Search(qf);varoid_idx=rc.FindField(oid_field);while(rc.MoveNext()){varoid=(long)rc.Current[oid_idx];varlc_oid=rc.Current.GetObjectID();lc_oids.Add(lc_oid);}rc.Dispose();mmDict[fl_lc]=lc_oids;break;}}}}varmmIdSet=MapMemberIDSet.FromDictionary(mmDict);linkChartView.SetRootNodes(mmIdSet);});
Append to Link Chart from FFP Results
//using ArcGIS.Core.Data.Knowledge.Extensions;varlinkChartView=MapView.Active;awaitQueuedTask.Run(async()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="Append to Link Chart from FFP Results";//set up config//...varresults=kg.RunFilteredFindPaths(ffp_config);varpathsEntitiesAndRelationships=results.ExtractPathsEntitiesAndRelationships(null);//Create a KG layer id setvarkgLayerIdSet=KnowledgeGraphLayerIDSet.FromKnowledgeGraphIDSet(pathsEntitiesAndRelationships.ToKnowledgeGraphIDSet(KGResultContentFromFFP.EntitiesAndRelationships));varmap=linkChartView.Map;if(!map.CanAppendToLinkChart(kgLayerIdSet))return;//not compatiblemap.AppendToLinkChart(kgLayerIdSet);//switch layout algovaralgo=linkChartView.GetLinkChartLayout();if(algo!=KnowledgeLinkChartLayoutAlgorithm.Hierarchical_TopToBottom){//Change layout algo to match the default used by the UI after FFPawaitlinkChartView.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;awaitQueuedTask.Run(async()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="List out FFP Results by Path Length, Min Cost, Max Cost";//set up config//...varresults=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 costvarpath_by_len_indices=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingPathLength.Select(idx =>idx.index);varpath_by_min_cost=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingMinPathCost.Select(idx =>idx.index);varpath_by_max_cost=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingMaxPathCost.Select(idx =>idx.index);varx=0;StringBuildersb=newStringBuilder();foreach(varpath_indecesinnewList<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()}");elseif(x==1)sb.AppendLine($"Paths by min cost: {path_by_min_cost.Count()}");elseif(x==2)sb.AppendLine($"Paths by max cost: {path_by_max_cost.Count()}");x++;foreach(varpath_idxinpath_indeces){varpath=(ResultPath)results.MaterializePath(path_idx);sb.AppendLine($"Path[{path_idx}] length: {path.Length}, min: {path.MinCost} max: {path.MaxCost}");varg=0;foreach(varrel_groupinpath.RelationshipGroups){varfirst_entity=$"({rel_group.FirstEntity.TypeName}:{rel_group.FirstEntity.Uid})";varsecond_entity=$"({rel_group.SecondEntity.TypeName}:{rel_group.SecondEntity.Uid})";foreach(varrelationinrel_group.Relationships){sb.Append($" [{g++}] ");vararrow=relation.SameDirectionAsPath?"->":"<-";varrel_uid=FormatUID(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");}}}}});}stringFormatUID(stringid){id=id.ToUpperInvariant();if(!id.StartsWith('{'))id='{'+id;if(!id.EndsWith('}'))id+='}';returnid;
List out FFP Results Origin, Destination, Other Entities
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(async()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="List out FFP Results Origin, Destination, Other Entities";//set up config//...varresults=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 costvarpath_by_len_indices=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingPathLength.Select(idx =>idx.index);varpath_by_min_cost=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingMinPathCost.Select(idx =>idx.index);varpath_by_max_cost=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingMaxPathCost.Select(idx =>idx.index);varx=0;StringBuildersb=newStringBuilder();foreach(varpath_indecesinnewList<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()}");elseif(x==1)sb.AppendLine($"Entities by min cost: {path_by_min_cost.Count()}");elseif(x==2)sb.AppendLine($"Entities by max cost: {path_by_max_cost.Count()}");x++;foreach(varpath_idxinpath_indeces){varpath=(ResultPath)results.MaterializePath(path_idx);sb.AppendLine($"Path[{path_idx}] length: {path.Length}, min: {path.MinCost} max: {path.MaxCost}");varsorted_set=newSortedSet<ulong>();sorted_set.Add((ulong)path_idx);varper=results.ExtractPathsEntitiesAndRelationships(sorted_set);varorigin_dest_uids=newList<string>();varsep="";sb.Append(" Origin EntitiesUIDs: ");foreach(varidxinper.PathsOriginEntitiesUIDsIndexes){//See 'List out FFP Results by Path Length, Min Cost, Max Cost' for//FormatID method abovevaruid=FormatID(per.EntitiesUIDs[idx].ToString());origin_dest_uids.Add(uid);varorigin=$"{sep}{per.EntityTypeNames[per.EntityTypes[idx]]}:{uid}";sep=", ";sb.Append($"{origin}");}sb.AppendLine("");sep="";sb.Append(" Destination EntitiesUIDs: ");foreach(varidxinper.PathsDestinationEntitiesUIDsIndexes){varuid=FormatID(per.EntitiesUIDs[idx].ToString());origin_dest_uids.Add(uid);vardest=$"{sep}{per.EntityTypeNames[per.EntityTypes[idx]]}:{uid}";sep=", ";sb.Append($"{dest}");}sb.AppendLine("");sep="";varidx2=0;sb.Append(" Other EntitiesUIDs: ");boolwereAnyOthers=false;foreach(varraw_uidinper.EntitiesUIDs){varuid=FormatID(raw_uid.ToString());if(!origin_dest_uids.Contains(uid)){varother=$"{sep}{per.EntityTypeNames[per.EntityTypes[idx2]]}:{uid}";sep=", ";sb.Append($"{other}");wereAnyOthers=true;}idx2++;}if(!wereAnyOthers)sb.Append(" <<none>>");//sb.AppendLine("");varentity_str=sb.ToString();System.Diagnostics.Debug.WriteLine(entity_str);sb.Clear();sep="";}}});
List out FFP Results Relationships
//using ArcGIS.Core.Data.Knowledge.Extensions;awaitQueuedTask.Run(async()=>{varffp_config=newCIMFilteredFindPathsConfiguration();ffp_config.Name="List out FFP Results Relationships";//set up config//...varresults=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 costvarpath_by_len_indices=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingPathLength.Select(idx =>idx.index);varpath_by_min_cost=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingMinPathCost.Select(idx =>idx.index);varpath_by_max_cost=(IEnumerable<long>)results.PathIndicesOrderedByIncreasingMaxPathCost.Select(idx =>idx.index);varx=0;StringBuildersb=newStringBuilder();foreach(varpath_indecesinnewList<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()}");elseif(x==1)sb.AppendLine($"Relationships by min cost: {path_by_min_cost.Count()}");elseif(x==2)sb.AppendLine($"Relationships by max cost: {path_by_max_cost.Count()}");x++;foreach(varpath_idxinpath_indeces){varpath=(ResultPath)results.MaterializePath(path_idx);sb.AppendLine($"Path[{path_idx}] length: {path.Length}, min: {path.MinCost} max: {path.MaxCost}");varsorted_set=newSortedSet<ulong>();sorted_set.Add((ulong)path_idx);varper=results.ExtractPathsEntitiesAndRelationships(sorted_set);varidx=0;foreach(varrel_uidinper.RelationshipsUIDs){sb.Append($" RelationshipsUIDs[{idx}]: ");varuid=FormatID(rel_uid.ToString());varrel_info=$"{per.RelationshipTypeNames[per.RelationshipTypes[idx]]}:{uid}";sb.Append($"{rel_info}\r\n");//From entity:varentity_idx=per.RelationshipsFrom[idx];varorigin_uid=FormatID(per.EntitiesUIDs[entity_idx].ToString());varorigin=$"{per.EntityTypeNames[per.EntityTypes[entity_idx]]}:{origin_uid}";sb.Append($" RelationshipsFrom: {origin}\r\n");//To entityentity_idx=per.RelationshipsTo[idx];vardest_uid=FormatID(per.EntitiesUIDs[entity_idx].ToString());vardest=$"{per.EntityTypeNames[per.EntityTypes[entity_idx]]}:{dest_uid}";sb.Append($" RelationshipsTo: {dest}\r\n");idx++;}varrel_str=sb.ToString();System.Diagnostics.Debug.WriteLine(rel_str);sb.Clear();}}});}stringFormatID(stringid){id=id.ToUpperInvariant();if(!id.StartsWith('{'))id='{'+id;if(!id.EndsWith('}'))id+='}';returnid;