Note: Sign in to access the data in this sample. username
password
Getting Started
A knowledge graph allows you work with a graph network.
This network connects people, places, and things
(represented by entities) with each other through
relationships that define how they are associated.
Both entities and relationships can have associated properties.
An entity with a spatial location can be connected with other entities that do not have a spatial location.
This sample demonstrates the two methods for querying a knowledge graph: executeQuery() and executeQueryStreaming(). Both query and streaming query use an an Esri implementation of openCypher to find patterns in graph data.
The sample dataset contains observations of bumble bees made at locations around the United States. Each observation was made and verified by users and is of a specific species of bumble bee.
For additional information on working with knowledge graph services see:
- Write an openCypher query for more on working with openCypher and knowledge graphs.
- Introduction to Knowledge Graph in the JavaScript Maps SDK.
- Search a knowledge graph
- Edit knowledge graph data
- Working with knowledge graph layer
- Get started with ArcGIS Knowledge Server for overview of ArcGIS Knowledge for ArcGIS Enterprise.
- Hosted Knowledge Graph Service for information on managing knowledge graph services via ArcGIS Enterprise and the REST API.
- Get started with ArcGIS Knowledge (ArcGIS Pro) for information on ArcGIS Knowledge in ArcGIS Pro.
How to use this sample
Sign in
The data in this example is secured, as most knowledge graph data will be since the ArcGIS Knowledge Graph Server license is required. Therefore, the first step is to sign in to load the data.
In this sample sign in with the following credentials: username
password
.
After signing in, the results section will update with the data model and service definition of the knowledge graph.
Query
The query defines the graph pattern to match. This pattern is a traversal of entity types and relationships that connect them.
In this sample, the default pattern is to match any entities of the type user
that are related to Observation
entities through an observed
or reviewed
relationship.
The relationship direction specifies that we are only interested in relationships going from User
to Observation
.
The next part of the query is any conditions to apply to the pattern. The condition can be on any property of the entities or
relationships in the pattern. In this example we are only interested in the Observation
entities where the quality
is 'research'.
Streaming
Toggle the streaming query.
The streaming query accepts bind parameter as variables in the query string. Bind parameters specify a set of data to be included in the query. They are particularly helpful when trying to execute a query with a very large argument, such as a large set of IDs or intersecting a complex geometry. The geometry can be defined separately and included in the query with a variable.
To use a geometry bind parameter, the entity type in the where clause must contain the shape property (indicating it is a spatial entity).
In this knowledge graph, the Observation
entity type is the only spatial entity type.
This query returns the users who made or verified observations within the bounding polygon. The map provides the polygon to use in the spatial query. Change the location or size of the polygon to modify the query results.
See bindParameters for more information.
How it Works
The first step is to connect to a knowledge graph using fetchKnowledgeGraph.
/**
* Initialization function that connects to a knowledge graph and displays the data model and service definition.
* The data model is used to populate the inputs in the query builder.
*/
require([
"esri/rest/knowledgeGraphService",
], (KGModule ) => {
//url to the knowledge graph server
const url = "https://sampleserver7.arcgisonline.com/server/rest/services/Hosted/BumbleBees/KnowledgeGraphServer"
const init = async () => {
//get the knowledge graph data model and service definition.
knowledgeGraph = await KGModule.fetchKnowledgeGraph(url);
//display the data model and service definition for the knowledge graph
dataDiv.innerHTML = `<h3>Knowledge Graph</h3><calcite-tree>${buildList(knowledgeGraph, false,true)}</calcite-tree>`;
}
init()
...
});
Query
Query executes a query against the knowledge graph.
The query string is in openCypher.
The default query in this sample finds and returns all of the users who have made or reviewed
research grade observations of bumble bees.
MATC
.
Note: ArcGIS Knowledge does not support all aspects of the openCypher query language. For example, queries can't be used to update the knowledge graph, only to return values. See Write an openCypher query for more on working with openCypher and knowledge graphs.
/**
* Basic query to return the selected entities or relationships that match the pattern.
* Query is limited by the maxRecordCount parameter in the serviceDefinition of the graph.
*/
document.getElementById('query-button').addEventListener('click', async (e) => {
query = constructCypher()
const searchResults = await KGModule.executeQuery(knowledgeGraph, {
openCypherQuery: query,
})
//display results
dataDiv.innerHTML = `<h3>Query Results</h3><calcite-tree>${buildList(searchResults.resultRows, false, true)}</calcite-tree>`;
})
Streaming Query
Streaming query
returns results in small chunks allowing the client
to begin processing the data returned immediately rather than waiting for the entire result set to be returned before processing.
Streaming is faster, more efficient, and will retrieve all matching records, even if the total exceeds query limits set in the service definition.
Another benefit of streaming is that the request is encoded which means that it is far smaller than a traditional
HTTP GET or JSON POST body. This is especially important when trying to do a query on a very large argument,
such as a large set of IDs or intersecting a complex geometry.
In this example the default streaming query returns users who have made or verified observations of bumblebees within a
specific geographic area. This geographic area is denoted by a variable in the query string, with the
geometry defining the area attached to the query through a bind parameter.
MATC
/**
* Streaming query to return the selected entities or relationships that match the pattern defined in the query.
* It uses the bindParameter property to either bind geometry from the sketch on the map to the query to perform a spatial query on the graph
* or to bind a list of ids to query within.
* Streaming query has more options to refine the query results.
* Streaming query also has much higher performance when working with large datasets.
* It returns the data in chunks that can be processed as they are returned.
*/
document.getElementById('streaming-query-button').addEventListener('click', async (e) => {
bindParameters = {}
query = constructCypher(true)
//create a geometry from the sketch layer as the bind parameter
const rings = []
for (graphic of graphicsLayer.graphics.items) {
//convert the geometry to wgs84 if necessary
const geom = graphic.geometry.spatialReference.isWGS84
? graphic.geometry
: webMercatorUtils.webMercatorToGeographic(graphic.geometry);
rings.push(geom.rings[0])
console.log(geom.rings)
}
bindParameters['userGeometry'] = new Polygon({ rings: rings })
//execute the query and display the results
const searchResults = await KGModule.executeQueryStreaming(knowledgeGraph, {
openCypherQuery: query,
bindParameters: bindParameters
})
dataDiv.innerHTML = '';
readStream(searchResults);
})
Each chunk returned by a streaming query is a readable stream that must be read before the results can be used. After the chunk is read it can be used in other client side processing. In this case it is used to create an HTML display of the result.
// a function to read the stream returned from the streaming query
const readStream = async (streamingQueryResult, method) => {
//create the reader
let reader = streamingQueryResult.resultRowsStream.getReader();
//try to read the stream
try {
while (true) {
//read the stream
const { done, value } = await reader.read();
//create the output list from the read stream.
dataDiv.innerHTML += `<h3>Query Results</h3><calcite-tree>${buildList(value, false, true)}</calcite-tree>`
//stop reader when the stream is done
if (done) {
break;
}
}
// if there is an error in returning the stream or the stream is aborted
} catch (err) {
if (err.name === "AbortError") {
console.log("Request aborted as expected");
} else {
throw err;
}
}
};