stringurl=@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));try{//Open a connectionusing(varkg=new KnowledgeGraph(kg_props)){//TODO...use the KnowledgeGraph}}catch(GeodatabaseNotFoundOrOpenedExceptionex){ System.Diagnostics.Debug.WriteLine(ex.ToString());}});
Getting a Connection from a KnowledgeGraphLayer
varkgLayer= MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();
QueuedTask.Run(()=>{// use the layer directlyvardatastore= 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()as KnowledgeGraph;//TODO use KnowledgeGraph}else{//try standalone tablevarstbl= kgLayer?.GetStandaloneTablesAsFlattenedList()?.FirstOrDefault();if(stbl!=null){using(vartbl= stbl.GetTable())kg= tbl.GetDatastore()as KnowledgeGraph;//TODO use KnowledgeGraph}}});
Retrieving GDB FeatureClasses and Definitions
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=new KnowledgeGraph(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(var fc_def in fc_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=new KnowledgeGraphConnectionProperties(new Uri(url));//Connect to the KnowledgeGraph datastore//KnowledgeGraph datastores contain tables and feature classesusing(varkg=new KnowledgeGraph(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(var tbl_def in tbl_defs){vartbl_name= tbl_def.GetName();using(varfc= kg.OpenDataset<Table>(tbl_name)){//TODO - use the table}}}});
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){//TODO use KG data model...}}});
Get Data Model Properties
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(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
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(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_info is KnowledgeGraphNativeIdentifier kg_ni){ System.Diagnostics.Debug.WriteLine($"IdentifierInfo: KnowledgeGraphNativeIdentifier");}elseif(kg_id_info is KnowledgeGraphUniformIdentifier kg_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=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(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(var kvp in dict_types){varmeta_entity_type= kvp.Value;if(meta_entity_type.GetRole()== KnowledgeGraphNamedObjectTypeRole.Provenance){//TODO - use the provenance entity typevarname= meta_entity_type.GetName();}}}}});
Get Whether KG Supports Provenance
internalstringGetProvenanceEntityTypeName(KnowledgeGraphDataModelkg_dm){varentity_types= kg_dm.GetMetaEntityTypes();foreach(var entity_type in entity_types){if(entity_type.Value.GetRole()== KnowledgeGraphNamedObjectTypeRole.Provenance)return entity_type.Value.GetName();}return"";}internalboolKnowledgeGraphSupportsProvenance(KnowledgeGraphkg){//if there is a provenance entity type then the KnowledgeGraph//supports provenancereturn!string.IsNullOrEmpty(
GetProvenanceEntityTypeName(kg.GetDataModel()));}
Get KnowledgeGraph Entity Types
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){vardict_types= kg_dm.GetEntityTypes();foreach(var kvp in dict_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 Whether KG Has a Document Type
internalstringGetDocumentEntityTypeName(KnowledgeGraphDataModelkg_dm){varentity_types= kg_dm.GetEntityTypes();foreach(var entity_type in entity_types){varrole= entity_type.Value.GetRole();if(role== KnowledgeGraphNamedObjectTypeRole.Document)return entity_type.Value.GetName();}return"";//Unusual - probably Neo4j user-managed}internalboolKnowledgeGraphHasDocumentType(KnowledgeGraphkg){//uncommon for there not to be a document typereturn!string.IsNullOrEmpty(
GetDocumentEntityTypeName(kg.GetDataModel()));}
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 parameterprotectedboolGetEntityIsDocument(KnowledgeGraphEntityValueentity,stringdocumentNameType=""){if(string.IsNullOrEmpty(documentNameType))returnfalse;return entity.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 parameterprotectedboolHasGeometry(KnowledgeGraphNamedObjectTypekg_named_obj){varprops= kg_named_obj.GetProperties();return props.Any(prop => prop.FieldType == FieldType.Geometry);}
Get KnowledgeGraph Relationship Types
QueuedTask.Run(()=>{//Create a connection propertiesvarkg_props=new KnowledgeGraphConnectionProperties(new Uri(url));using(varkg=new KnowledgeGraph(kg_props)){//Get the KnowledgeGraph Data Modelusing(varkg_dm= kg.GetDataModel()){vardict_types= kg_dm.GetRelationshipTypes();foreach(var kvp in dict_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(var end_point in end_points){ System.Diagnostics.Debug.WriteLine($"Origin: '{end_point.GetOriginEntityTypeName()}', "+$"Destination: '{end_point.GetDestinationEntityTypeName()}'");}}}}});
Create a KG Layer containing all Entity and Relate types
QueuedTask.Run(()=>{//With a connection to a KG established or source uri available...//Create a KnowledgeGraphLayerCreationParamsvarkg_params=new KnowledgeGraphLayerCreationParams(kg){Name="KG_With_All_Types",IsVisible=false};//Orvarkg_params2=new KnowledgeGraphLayerCreationParams(new Uri(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
QueuedTask.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 records dict.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=new KnowledgeGraphLayerCreationParams(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
QueuedTask.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//NOT ALLOWED - can only be a child of a KG layervarfl_params_w_kg=new FeatureLayerCreationParams(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 exception LayerFactory.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=new KnowledgeGraphLayerCreationParams(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;
QueuedTask.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 records dict2.Add("Enity_Or_Relate_Type_Name2",newList<long>());//Empty list means all records dict2.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;
QueuedTask.Run(()=>{//Get the feature classvarfc= featureLyer.GetFeatureClass();// is it part of a KnowledgeGraph?varisPartOfKG= fc.GetIsKnowledgeGraphDataset();});
Get KG Datastore
varkgLayer= MapView.Active.Map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kgLayer==null)return;
QueuedTask.Run(()=>{// get the datastorevarkg= kgLayer.GetDatastore();// now submit a search or a query// kg.SubmitSearch// kg.SubmitQuery});
Get KG Service uri
kgLayer.GetServiceUri();
SubLayers of a KnowledgeGraph Layer
varmap= MapView.Active.Map;varkgLayer= map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kgLayer==null)return;if(map.MapType == MapType.LinkChart){// if map is of MapType.LinkChart then the first level// children of the kgLayer are of type LinkChartFeatureLayervarchildLayers= kgLayer.Layers;foreach(var childLayer in childLayers){if(childLayer is LinkChartFeatureLayer lcFeatureLayer){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// kgLayer are the standard Featurelayer and StandAloneTablevarchidlren= kgLayer.GetMapMembersAsFlattenedList();foreach(var child in chidlren){if(child is FeatureLayer fl){// TODO - process the feature layer}elseif(child is StandaloneTable st){// TODO - process the standalone table}}}
Create a LinkChart from a subset of an existing LinkChart IDSet
varmap= MapView.Active.Map;if(map.MapType != MapType.LinkChart)return;// find the KG layervarkgLayer= map.GetLayersAsFlattenedList().OfType<KnowledgeGraphLayer>().FirstOrDefault();if(kgLayer==null)return;// find the first LinkChartFeatureLayer in the KG layervarlcFeatureLayer= kgLayer.GetLayersAsFlattenedList().OfType<LinkChartFeatureLayer>().FirstOrDefault();if(lcFeatureLayer!=null)return;
QueuedTask.Run(()=>{// get the KGvarkg= kgLayer.GetDatastore();// 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(kg, newDict);// now create a new link chart using just this subset of records MapFactory.Instance.CreateLinkChart("subset LinkChart", kg, newIDSet);}});
Graph Query and Text Search
Submit a Graph Query
//On the QueuedTask...//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=new KnowledgeGraphQueryFilter(){QueryText=query};//Optionally - u can choose to include provenance in the results//(_if_ the KG has provenance - otherwise the query will fail)if(includeProvenanceIfPresent){//see "Get Whether KG Supports Provenance" snippetif(KnowledgeGraphSupportsProvenance(kg)){//Only include if the KG has provenance
kg_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(await kg_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" snippet
ProcessKnowledgeGraphRowValue(retval);}}}}//WaitForRowsAsync}//SubmitQuery
Submit a Text Search
//On the QueuedTask...//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=new KnowledgeGraphSearchFilter(){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(await kg_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]as KnowledgeGraphEntityValue;varentity_type= entity.GetTypeName();varrecord=newList<string>();//discover keys(aka "fields") dynamically via GetKeysforeach(var prop_name in entity.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
QueuedTask.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=new KnowledgeGraphQueryFilter(){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(await kgRowCursor.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]as KnowledgeGraphEntityValue;//note: some user-managed graphs do not have objectids oids.Add(cell_phone.GetObjectID());}}}}//create a query filter using the oidsif(oids.Count >0){//select them on the layervarqf=new QueryFilter(){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= kg_layer.GetLayersAsFlattenedList().OfType<FeatureLayer>().First(l => l.Name =="PhoneNumber");//perform the selection phone_number_fl.Select(qf);}});
Use Bind Parameters with an Open Cypher Query
QueuedTask.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=new KnowledgeGraphQueryFilter(){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=new KnowledgeGraphArrayValue(); 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(await kgRowCursor.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]as KnowledgeGraphEntityValue;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
QueuedTask.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=new KnowledgeGraphQueryFilter(){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=new KnowledgeGraphArrayValue();
kg_oid_array.AddRange(oids);
kg_qry_filter.BindParameters["object_ids"]=kg_oid_array;
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(await kgRowCursor.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]as KnowledgeGraphEntityValue;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 kg_rc = kg.SubmitQuery(kg_qf)) {//using (var kg_rc = kg.SubmitSearch(kg_sf)) {//...//wait for rows to be returned from the server//"auto-cancel" after 20 secondsvarcancel=new CancellationTokenSource(new TimeSpan(0,0,20));//catch TaskCanceledExceptiontry{while(await kg_rc.WaitForRowsAsync(cancel.Token)){//check for row eventswhile(kg_rc.MoveNext()){using(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" snippet
ProcessKnowledgeGraphRowValue(retval);}}}}}//Timeout expiredcatch(TaskCanceledExceptiontce){//Handle cancellation as needed}
cancel.Dispose();
Process a KnowledgeGraphRow Value
//Base class for entities and relationships//(including documents and provenance)publicvoidProcessGraphNamedObjectValue(KnowledgeGraphNamedObjectValuekg_named_obj_val){if(kg_named_obj_val is KnowledgeGraphEntityValue kg_entity){varlabel= kg_entity.GetLabel();//TODO - use label}elseif(kg_named_obj_val is KnowledgeGraphRelationshipValue kg_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 objectspublicvoidProcessGraphObjectValue(KnowledgeGraphObjectValuekg_obj_val){switch(kg_obj_val){case KnowledgeGraphEntityValue kg_entity:
ProcessGraphNamedObjectValue(kg_entity);break;case KnowledgeGraphRelationshipValue kg_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(var key in keys)
ProcessKnowledgeGraphRowValue(kg_obj_val[key]);//Recurse}//Process a KnowledgeGraphValue from a query or searchpublicvoidProcessGraphValue(KnowledgeGraphValuekg_val){switch(kg_val){case KnowledgeGraphPrimitiveValue kg_prim://KnowledgeGraphPrimitiveValue not currently used in//query and search
ProcessKnowledgeGraphRowValue(kg_prim.GetValue());//Recursereturn;case KnowledgeGraphArrayValue kg_array:varcount= kg_array.GetSize();//Recursively process each value in the arrayfor(ulongi=0;i<count;i++)
ProcessKnowledgeGraphRowValue(kg_array[i]);//Recursereturn;case KnowledgeGraphPathValue kg_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;case KnowledgeGraphObjectValue kg_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 arraypublicvoidProcessKnowledgeGraphRowValue(objectvalue){switch(value){//Graph value?case KnowledgeGraphValue kg_val:varkg_type= kg_val.KnowledgeGraphValueType.ToString();
System.Diagnostics.Debug.WriteLine($"KnowledgeGraphValue: '{kg_type}'");
ProcessGraphValue(kg_val);//Recursereturn;//Primitive types...add additional logic as neededcase System.DBNull dbn:
System.Diagnostics.Debug.WriteLine("DBNull.Value");return;casestring str:
System.Diagnostics.Debug.WriteLine($"'{str}' (string)");return;caselong l_val:
System.Diagnostics.Debug.WriteLine($"{l_val} (long)");return;caseint i_val:
System.Diagnostics.Debug.WriteLine($"{i_val} (int)");return;caseshort s_val:
System.Diagnostics.Debug.WriteLine($"{s_val} (short)");return;casedouble d_val:
System.Diagnostics.Debug.WriteLine($"{d_val} (double)");return;casefloat f_val:
System.Diagnostics.Debug.WriteLine($"{f_val} (float)");return;case DateTime dt_val:
System.Diagnostics.Debug.WriteLine($"{dt_val} (DateTime)");return;case DateOnly dt_only_val:
System.Diagnostics.Debug.WriteLine($"{dt_only_val} (DateOnly)");return;case TimeOnly tm_only_val:
System.Diagnostics.Debug.WriteLine($"{tm_only_val} (TimeOnly)");return;case DateTimeOffset dt_tm_offset_val:
System.Diagnostics.Debug.WriteLine($"{dt_tm_offset_val} (DateTimeOffset)");return;case System.Guid guid_val:varguid_string= guid_val.ToString("B");
System.Diagnostics.Debug.WriteLine($"'{guid_string}' (Guid)");return;case Geometry geom_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 kg_rc = kg.SubmitQuery(kg_qf)) {//using (var kg_rc = kg.SubmitSearch(kg_sf)) {// ...wait for rows ...// while (await kg_rc.WaitForRowsAsync()) {// ...rows have been retrieved// while (kg_rc.MoveNext()) {// ...get the current KnowledgeGraphRow// using (var graph_row = kg_rc.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 thatvarmap= 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;
varmv= MapView.Active;// a MapView can encapsulate a link chart IF it's map// is of type MapType.LinkChartvarmap= mv.Map;varisLinkChart= map.MapType == MapType.LinkChart;// or use the following// var isLinkChart = map.IsLinkChart;
QueuedTask.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 it mv.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
QueuedTask.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
QueuedTask.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
//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>>();
QueuedTask.Run(async()=>{using(varkg= kg_layer.GetDatastore()){vargraphQuery=new KnowledgeGraphQueryFilter(){QueryText=qry};using(varkgRowCursor= kg.SubmitQuery(graphQuery)){while(await kgRowCursor.WaitForRowsAsync()){while(kgRowCursor.MoveNext()){using(vargraphRow= kgRowCursor.Current){// process the rowvarcnt_val=(int)graphRow.GetCount();for(intv=0;v<cnt_val;v++){varobj_val= graphRow[v]as KnowledgeGraphNamedObjectValue;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, dict);//Create the link chart and show itvarlinkChart= MapFactory.Instance.CreateLinkChart("KG With ID Set", kg, 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 serverstringurl=@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";
QueuedTask.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_props=new KnowledgeGraphConnectionProperties(new Uri(url));try{//Open a connectionusing(varkg=new KnowledgeGraph(kg_props)){//Add all entities to the link chartvaridSet= KnowledgeGraphLayerIDSet.FromKnowledgeGraph( kg, KnowledgeGraphFilterType.AllEntities);//Create the new link chart and show itvarnewLinkChart= MapFactory.Instance.CreateLinkChart("KG from Template", kg, 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 records
dict.Add("made_call",null);//null list means all records// or specific records - however the ids are obtained
dict.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";
QueuedTask.Run(async()=>{using(varkg= kg_layer.GetDatastore()){vargraphQuery=new KnowledgeGraphQueryFilter(){QueryText=qry2};using(varkgRowCursor= kg.SubmitQuery(graphQuery)){while(await kgRowCursor.WaitForRowsAsync()){while(kgRowCursor.MoveNext()){using(vargraphRow= kgRowCursor.Current){varobj_val= graphRow[0]as KnowledgeGraphNamedObjectValue;varoid=(long)obj_val.GetObjectID(); dict["Suspects"].Add(oid);}}}}//make an ID Set to append to the LinkChartvaridSet= KnowledgeGraphLayerIDSet.FromDictionary(kg, 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
QueuedTask.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
QueuedTask.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)});