Search and query a knowledge graph service

There are two ways to retrieve records from a knowledge graph. Search allows you to run a free text search against the knowledge graph. Query provides a more nuanced way to retrieve records in the form of an openCypher query executed against the knowledge graph. Both search and query have two modes: non-streaming and streaming. Streaming search and streaming query return 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 the search and 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.

Use GraphSearchStreaming to search the properties of both entities and relationships in the graph using the executeSearchStreaming() method. Additional optional search parameters such as specifying a list of entity or relationship types to search within can further constrain the search. The most efficient way to search a knowledge graph is with a streaming search.

Expand
Use dark colors for code blocksCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230  // define the search terms  const search = new StreamingSearch({  searchQuery: "solar",  typeCategoryFilter: "both",  // optional parameters  returnSearchContext: false,  start: 1, //start at the first record  num: 200, //return 200 records.  namedTypesFilter: ["Company", "Supplier", "Part"],  globalIdsFilter: ["aiw-924", "esj-856", "snh-571", "hnk-9751", "pyo-7884", "hjl-2541"],  });   // search the knowledge graph  KnowledgeGraphModule.executeSearchStreaming(  // knowledge graph resources  knowledgeGraph,  // search parameters  search,  ).then((streamingSearchResult) => {  // the result of a streaming search is a readableStream which must be read to access the data.  readStream(streamingSearchResult);  }); 
Expand

Query

Retrieve a more specific subset of entities and relationships or their properties using the executeQueryStreaming() method. Querying a graph uses the Esri implementation of openCypher query which supports read-only operations. Query provides much more flexibility in what results are returned from the graph and the structure of the returned data. For example, consider a graph of a supply chain containing the entities manufacturing Plant which makes a Part that is bought by a Supplier; and there is a relationship produces between the plant and the part it produces and a relationship buys_part between the supplier and the plant where it purchases the part.

To find the first ten entities of the Supplier type, you could use the query MATCH (m:Supplier) RETURN m LIMIT 10. To discover which parts(p) are produced with by which plants (pl), you can match the entities through the produces relationship with a query such as MATCH (pl:Plant)-[ :produces]->(p) RETURN pl,p. GraphQueryStreaming also provides the ability to bind parameters to the query such as a bounding box. For example, to find all the suppliers located in area of Washington DC, use an intersection query and pass a polygon that covers the Washington DC area as a bind parameter. See GraphQueryStreaming for additional query parameters.

Expand
Use dark colors for code blocksCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230  // select all Supplier's that are in the Washington DC area and the parts that they buy  const query = `MATCH (s:Supplier)-[:buys_part]-(p:Part)  esri.graph.ST_Intersects($geom, s.geometry)  RETURN s,p`;   KnowledgeGraphModule.executeQueryStreaming(knowledgeGraph, {  openCypherQuery: query,  bindParameters: {  //bounding box around Washington DC  geom: new Polygon({  rings: [  [  [38, -78],  [39, -78],  [39, -76],  [-38, -76],  [-38, -78],  ],  ],  }),  },  }).then((streamingQueryResult) => {  // the result of a streaming query is a readableStream which must be read to access the data.  readStream(streamingQueryResult);  }); 
Expand

Working with stream results

The result of a streaming search or a streaming query is a GraphQueryStreamingResult which contains a readable stream that must be read using a getReader() function to access the data. The readable stream will return chunks of records until all records have been returned. Each chunk may be processed immediately, such as adding data to a table or adding entities with geometry to a map.

Expand
Use dark colors for code blocksCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230  // a function to read the stream returned from the search  const readStream = async (streamingQueryResult) => {  let time = Date.now();  let reader = streamingQueryResult.resultRowsStream.getReader();  try {  while (true) {  const { done, value } = await reader.read();  if (done) {  console.log(  `Stream completed and closed: ${(Date.now() - time) / 1000} seconds`,  value,  );  break;  }  // begin working with the data from the returned chunk immediately.  // list the parts bought by each supplier  let supplierParts = [];   // each element of the result array will contain one supplier and one part it buys  for (let v in value) {  let supplier = value[v][0].properties.Name;  let part = value[v][1].properties.Name;  if (!(supplier in supplierParts)) {  supplierParts[supplier] = [];  }   // collect parts by supplier that buys them  supplierParts[supplier].push(part);  }  // make a table that lists the suppliers and the parts they buy  let table = document.getElementById("supplierTableBody");  for (let supplier in supplierParts) {  table.appendChild(  `<tr><td>${supplier}</td><td>${supplierParts.supplier.join(", ")}</td>`,  );  }  // Entities that have geometry can be drawn on the map  addToMap(value);  // Since  }  // 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;  }  }  };   // function to add entities with geometry to a map  function addToMap(records) {  let features = [];  //extract the geometry from the returned results and add it to a feature layer  for (let i = 0; i < records.length; i++) {  let item = records[i][0];  let props = item.properties;  // if the returned item contains geometry,  //extract the geometry information to create features  if ("shape" in props) {  features.push({  geometry: {  type: props.shape.type,  x: props.shape.longitude,  y: props.shape.latitude,  },  attributes: props,  });  }  }   // create feature layer  let featureLayer = new FeatureLayer({  source: features,  renderer: {  type: "unique-value", // autocasts as new UniqueValueRenderer()  defaultSymbol: {  type: "simple-marker", // autocasts as new SimpleMarkerSymbol()  size: 2,  color: "#009816",  outline: null,  },  },  });  map.add(featureLayer);  } 
Expand

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.