ProSnippets KnowledgeGraph
UmaHarano edited this page Nov 6, 2023
·
1 revision
Language: C#
Subject: KnowledgeGraph
Contributor: ArcGIS Pro SDK Team <arcgisprosdk@esri.com>
Organization: esri, http://www.esri.com
Date: 10/16/2023
ArcGIS Pro: 3.2
Visual Studio: 2022
.NET Target Framework: .Net 6
string url =
@"https://acme.server.com/server/rest/services/Hosted/AcmeKnowledgeGraph/KnowledgeGraphServer";
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
try
{
//Open a connection
using (var kg = new KnowledgeGraph(kg_props))
{
//TODO...use the KnowledgeGraph
}
}
catch (GeodatabaseNotFoundOrOpenedException ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
});
var kgLayer = MapView.Active.Map.GetLayersAsFlattenedList()
.OfType<KnowledgeGraphLayer>().FirstOrDefault();
//KnowledgeGraphLayer is a composite layer - get the first
//child feature layer or standalone table
QueuedTask.Run(() =>
{
var featlayer = kgLayer?.GetLayersAsFlattenedList()?
.OfType<FeatureLayer>()?.FirstOrDefault();
KnowledgeGraph kg = null;
if (featlayer != null)
{
using (var fc = featlayer.GetFeatureClass())
kg = fc.GetDatastore() as KnowledgeGraph;
//TODO use KnowledgeGraph
}
else
{
//try standalone table
var stbl = kgLayer?.GetStandaloneTablesAsFlattenedList()?
.FirstOrDefault();
if (stbl != null)
{
using (var tbl = stbl.GetTable())
kg = tbl.GetDatastore() as KnowledgeGraph;
//TODO use KnowledgeGraph
}
}
});
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
//Connect to the KnowledgeGraph datastore
//KnowledgeGraph datastores contain tables and feature classes
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the featureclass definitions from the KG datastore
var fc_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 model
foreach (var fc_def in fc_defs)
{
var fc_name = fc_def.GetName();
using (var fc = kg.OpenDataset<FeatureClass>(fc_name))
{
//TODO - use the feature class
}
}
}
});
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
//Connect to the KnowledgeGraph datastore
//KnowledgeGraph datastores contain tables and feature classes
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the table definitions from the KG datastore
var tbl_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 model
foreach (var tbl_def in tbl_defs)
{
var tbl_name = tbl_def.GetName();
using (var fc = kg.OpenDataset<Table>(tbl_name))
{
//TODO - use the table
}
}
}
});
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using(var kg_dm = kg.GetDataModel())
{
//TODO use KG data model...
}
}
});
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using (var kg_dm = kg.GetDataModel())
{
var kg_name = System.IO.Path.GetFileName(
System.IO.Path.GetDirectoryName(kg_props.URL.ToString()));
System.Diagnostics.Debug.WriteLine(
$"\r\n'{kg_name}' Datamodel:\r\n-----------------");
var time_stamp = kg_dm.GetTimestamp();
var sr = 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()}");
}
}
});
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using (var kg_dm = kg.GetDataModel())
{
var kg_id_info = kg_dm.GetIdentifierInfo();
var kg_id_gen = kg_id_info.GetIdentifierGeneration();
if (kg_id_info is KnowledgeGraphNativeIdentifier kg_ni)
{
System.Diagnostics.Debug.WriteLine(
$"IdentifierInfo: KnowledgeGraphNativeIdentifier");
}
else if (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()}");
}
}
});
//Provenance entity type is stored as a MetaEntityType
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using (var kg_dm = kg.GetDataModel())
{
var dict_types = kg_dm.GetMetaEntityTypes();
//If there is no provenance then MetaEntityTypes will be
//an empty collection
foreach (var kvp in dict_types)
{
var meta_entity_type = kvp.Value;
if (meta_entity_type.GetRole() ==
KnowledgeGraphNamedObjectTypeRole.Provenance)
{
//TODO - use the provenance entity type
var name = meta_entity_type.GetName();
}
}
}
}
});
internal string GetProvenanceEntityTypeName(KnowledgeGraphDataModel kg_dm)
{
var entity_types = kg_dm.GetMetaEntityTypes();
foreach (var entity_type in entity_types)
{
if (entity_type.Value.GetRole() == KnowledgeGraphNamedObjectTypeRole.Provenance)
return entity_type.Value.GetName();
}
return "";
}
internal bool KnowledgeGraphSupportsProvenance(KnowledgeGraph kg)
{
//if there is a provenance entity type then the KnowledgeGraph
//supports provenance
return !string.IsNullOrEmpty(
GetProvenanceEntityTypeName(kg.GetDataModel()));
}
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using (var kg_dm = kg.GetDataModel())
{
var dict_types = kg_dm.GetEntityTypes();
foreach (var kvp in dict_types)
{
var entity_type = kvp.Value;
var role = entity_type.GetRole();
//note "name" will be the same name as the corresponding
//feature class or table in the KG's relational gdb model
var name = entity_type.GetName();
//etc
}
}
}
});
internal string GetDocumentEntityTypeName(KnowledgeGraphDataModel kg_dm)
{
var entity_types = kg_dm.GetEntityTypes();
foreach (var entity_type in entity_types)
{
var role = entity_type.Value.GetRole();
if (role == KnowledgeGraphNamedObjectTypeRole.Document)
return entity_type.Value.GetName();
}
return "";//Unusual - probably Neo4j user-managed
}
internal bool KnowledgeGraphHasDocumentType(KnowledgeGraph kg)
{
//uncommon for there not to be a document type
return !string.IsNullOrEmpty(
GetDocumentEntityTypeName(kg.GetDataModel()));
}
//Use GetDocumentEntityTypeName(KnowledgeGraphDataModel kg_dm) from
//the 'Get Whether KG Has a Document Type' snippet to
//get the documentNameType parameter
protected bool GetEntityIsDocument(KnowledgeGraphEntityValue entity,
string documentNameType = "")
{
if (string.IsNullOrEmpty(documentNameType))
return false;
return entity.GetTypeName() == documentNameType;
}
QueuedTask.Run(() =>
{
//Create a connection properties
var kg_props =
new KnowledgeGraphConnectionProperties(new Uri(url));
using (var kg = new KnowledgeGraph(kg_props))
{
//Get the KnowledgeGraph Data Model
using (var kg_dm = kg.GetDataModel())
{
var dict_types = kg_dm.GetRelationshipTypes();
foreach (var kvp in dict_types)
{
var rel_type = kvp.Value;
var role = rel_type.GetRole();
//note "name" will be the same name as the corresponding
//feature class or table in the KG's relational gdb model
var name = rel_type.GetName();
//etc.
//Get relationship end points
var end_points = rel_type.GetEndPoints();
foreach (var end_point in end_points)
{
System.Diagnostics.Debug.WriteLine(
$"Origin: '{end_point.GetOriginEntityTypeName()}', " +
$"Destination: '{end_point.GetDestinationEntityTypeName()}'");
}
}
}
}
});
//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...)
var query = "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 ignored
var kg_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" snippet
if (KnowledgeGraphSupportsProvenance(kg))
{
//Only include if the KG has provenance
kg_qf.ProvenanceBehavior =
KnowledgeGraphProvenanceBehavior.Include;//default is exclude
}
}
//submit the query - returns a KnowledgeGraphCursor
using (var kg_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 KnowledgeGraphRow
using (var graph_row = kg_rc.Current)
{
//Graph row is an array, process all returned values...
var val_count = (int)graph_row.GetCount();
for (int i = 0; i < val_count; i++)
{
var retval = graph_row[i];
//Process row value (note: recursive)
//See "Process a KnowledgeGraphRow Value" snippet
ProcessKnowledgeGraphRowValue(retval);
}
}
}
}//WaitForRowsAsync
}//SubmitQuery
//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.html
var kg_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 KnowledgeGraphCursor
using (var kg_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 KnowledgeGraphRow
using (var graph_row = kg_rc.Current)
{
//Graph row is an array, process all returned values...
var val_count = (int)graph_row.GetCount();
for (int i = 0; i < val_count; i++)
{
var retval = graph_row[i];
//Process row value (note: recursive)
//See "Process a KnowledgeGraphRow Value" snippet
ProcessKnowledgeGraphRowValue(retval);
}
}
}
}//WaitForRowsAsync
}//SubmitSearch
//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 seconds
var cancel = new CancellationTokenSource(new TimeSpan(0, 0, 20));
//catch TaskCanceledException
try
{
while (await kg_rc.WaitForRowsAsync(cancel.Token))
{
//check for row events
while (kg_rc.MoveNext())
{
using (var graph_row = kg_rc.Current)
{
//Graph row is an array, process all returned values...
var val_count = (int)graph_row.GetCount();
for (int i = 0; i < val_count; i++)
{
var retval = graph_row[i];
//Process row value (note: recursive)
//See "Process a KnowledgeGraphRow Value" snippet
ProcessKnowledgeGraphRowValue(retval);
}
}
}
}
}
//Timeout expired
catch (TaskCanceledException tce)
{
//Handle cancellation as needed
}
cancel.Dispose();
//Base class for entities and relationships
//(including documents and provenance)
public void ProcessGraphNamedObjectValue(
KnowledgeGraphNamedObjectValue kg_named_obj_val)
{
if (kg_named_obj_val is KnowledgeGraphEntityValue kg_entity)
{
var label = kg_entity.GetLabel();
//TODO - use label
}
else if (kg_named_obj_val is KnowledgeGraphRelationshipValue kg_rel)
{
var has_entity_ids = kg_rel.GetHasRelatedEntityIDs();
if (kg_rel.GetHasRelatedEntityIDs())
{
var origin_id = kg_rel.GetOriginID();
var dest_id = kg_rel.GetDestinationID();
//TODO - use ids
}
}
var id = kg_named_obj_val.GetID();
var oid = 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 model
var type_name = kg_named_obj_val.GetTypeName();
//TODO use id, object id, etc.
}
//Object values include entities, relationships, and anonymous objects
public void ProcessGraphObjectValue(KnowledgeGraphObjectValue kg_obj_val)
{
switch (kg_obj_val)
{
case KnowledgeGraphEntityValue kg_entity:
ProcessGraphNamedObjectValue(kg_entity);
break;
case KnowledgeGraphRelationshipValue kg_rel:
ProcessGraphNamedObjectValue(kg_rel);
break;
default:
//Anonymous objects
break;
}
//graph object values have a set of properties (equivalent
//to a collection of key/value pairs)
var keys = kg_obj_val.GetKeys();
foreach (var key in keys)
ProcessKnowledgeGraphRowValue(kg_obj_val[key]);//Recurse
}
//Process a KnowledgeGraphValue from a query or search
public void ProcessGraphValue(KnowledgeGraphValue kg_val)
{
switch (kg_val)
{
case KnowledgeGraphPrimitiveValue kg_prim:
//KnowledgeGraphPrimitiveValue not currently used in
//query and search
ProcessKnowledgeGraphRowValue(kg_prim.GetValue());//Recurse
return;
case KnowledgeGraphArrayValue kg_array:
var count = kg_array.GetSize();
//Recursively process each value in the array
for (ulong i = 0; i < count; i++)
ProcessKnowledgeGraphRowValue(kg_array[i]);//Recurse
return;
case KnowledgeGraphPathValue kg_path:
//Entities
var entity_count = kg_path.GetEntityCount();
//Recursively process each entity value in the path
for (ulong i = 0; i < entity_count; i++)
ProcessGraphObjectValue(kg_path.GetEntity(i));//Recurse
//Recursively process each relationship value in the path
var relate_count = kg_path.GetRelationshipCount();
for (ulong i = 0; i < relate_count; i++)
ProcessGraphObjectValue(kg_path.GetRelationship(i));//Recurse
return;
case KnowledgeGraphObjectValue kg_object:
ProcessGraphObjectValue(kg_object);//Recurse
return;
default:
var type_string = kg_val.GetType().ToString();
System.Diagnostics.Debug.WriteLine(
$"Unknown: '{type_string}'");
return;
}
}
//Process each value from the KnowledgeGraphRow array
public void ProcessKnowledgeGraphRowValue(object value)
{
switch (value)
{
//Graph value?
case KnowledgeGraphValue kg_val:
var kg_type = kg_val.KnowledgeGraphValueType.ToString();
System.Diagnostics.Debug.WriteLine(
$"KnowledgeGraphValue: '{kg_type}'");
ProcessGraphValue(kg_val);//Recurse
return;
//Primitive types...add additional logic as needed
case System.DBNull dbn:
System.Diagnostics.Debug.WriteLine("DBNull.Value");
return;
case string str:
System.Diagnostics.Debug.WriteLine($"'{str}' (string)");
return;
case long l_val:
System.Diagnostics.Debug.WriteLine($"{l_val} (long)");
return;
case int i_val:
System.Diagnostics.Debug.WriteLine($"{i_val} (int)");
return;
case short s_val:
System.Diagnostics.Debug.WriteLine($"{s_val} (short)");
return;
case double d_val:
System.Diagnostics.Debug.WriteLine($"{d_val} (double)");
return;
case float 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:
var guid_string = guid_val.ToString("B");
System.Diagnostics.Debug.WriteLine($"'{guid_string}' (Guid)");
return;
case Geometry geom_val:
var geom_type = geom_val.GeometryType.ToString();
var is_empty = geom_val.IsEmpty;
var wkid = geom_val.SpatialReference?.Wkid ?? 0;
System.Diagnostics.Debug.WriteLine(
$"geometry: {geom_type}, empty: {is_empty}, sr_wkid {wkid} (shape)");
return;
default:
//Blob? Others?
var type_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]);
Home | API Reference | Requirements | Download | Samples
-
Opening a Connection to a KnowledgeGraph
-
Getting a Connection from a KnowledgeGraphLayer
-
Retrieving FeatureClasses and Definitions
-
Retrieving Tables and Definitions
-
Retrieving the Data Model
-
Get Data Model Properties
-
Get Data Model Identifier Info
-
Get Data Model MetaEntityTypes/Provenance
-
Get Whether KG Supports Provenance
-
Get KnowledgeGraph Entity Types
-
Get Whether KG Has a Document Type
-
Check Whether A KG Entity Is a Document
-
Get KnowledgeGraph Relationship Types