@saschabrunnerch/arcgis-maps-sdk-js-ai-context 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -201
- package/bin/cli.js +157 -173
- package/contexts/4.34/{claude → skills}/arcgis-3d-advanced/SKILL.md +586 -586
- package/contexts/4.34/{claude → skills}/arcgis-advanced-layers/SKILL.md +431 -431
- package/contexts/4.34/{claude → skills}/arcgis-analysis-services/SKILL.md +607 -607
- package/contexts/4.34/{claude → skills}/arcgis-authentication/SKILL.md +301 -301
- package/contexts/4.34/{claude → skills}/arcgis-cim-symbols/SKILL.md +486 -486
- package/contexts/4.34/{claude → skills}/arcgis-coordinates-projection/SKILL.md +406 -406
- package/contexts/4.34/{claude → skills}/arcgis-core-maps/SKILL.md +739 -739
- package/contexts/4.34/{claude → skills}/arcgis-core-utilities/SKILL.md +732 -732
- package/contexts/4.34/{claude → skills}/arcgis-custom-rendering/SKILL.md +445 -445
- package/contexts/4.34/{claude → skills}/arcgis-editing-advanced/SKILL.md +702 -702
- package/contexts/4.34/{claude → skills}/arcgis-feature-effects/SKILL.md +393 -393
- package/contexts/4.34/{claude → skills}/arcgis-geometry-operations/SKILL.md +489 -489
- package/contexts/4.34/{claude → skills}/arcgis-imagery/SKILL.md +307 -307
- package/contexts/4.34/{claude → skills}/arcgis-interaction/SKILL.md +572 -572
- package/contexts/4.34/{claude → skills}/arcgis-knowledge-graphs/SKILL.md +582 -582
- package/contexts/4.34/{claude → skills}/arcgis-layers/SKILL.md +601 -601
- package/contexts/4.34/{claude → skills}/arcgis-map-tools/SKILL.md +668 -668
- package/contexts/4.34/{claude → skills}/arcgis-media-layers/SKILL.md +290 -290
- package/contexts/4.34/{claude → skills}/arcgis-portal-content/SKILL.md +679 -679
- package/contexts/4.34/{claude → skills}/arcgis-scene-effects/SKILL.md +512 -512
- package/contexts/4.34/{claude → skills}/arcgis-smart-mapping/SKILL.md +686 -686
- package/contexts/4.34/skills/arcgis-starter-app/SKILL.md +273 -0
- package/contexts/4.34/skills/arcgis-starter-app-extended/SKILL.md +649 -0
- package/contexts/4.34/{claude → skills}/arcgis-tables-forms/SKILL.md +877 -877
- package/contexts/4.34/{claude → skills}/arcgis-time-animation/SKILL.md +722 -722
- package/contexts/4.34/{claude → skills}/arcgis-utility-networks/SKILL.md +301 -301
- package/contexts/4.34/{claude → skills}/arcgis-visualization/SKILL.md +580 -580
- package/contexts/4.34/{claude → skills}/arcgis-widgets-ui/SKILL.md +574 -574
- package/lib/installer.js +294 -379
- package/package.json +45 -45
- package/contexts/4.34/copilot/arcgis-3d.instructions.md +0 -267
- package/contexts/4.34/copilot/arcgis-analysis.instructions.md +0 -294
- package/contexts/4.34/copilot/arcgis-arcade.instructions.md +0 -234
- package/contexts/4.34/copilot/arcgis-authentication.instructions.md +0 -187
- package/contexts/4.34/copilot/arcgis-cim-symbols.instructions.md +0 -177
- package/contexts/4.34/copilot/arcgis-core-maps.instructions.md +0 -246
- package/contexts/4.34/copilot/arcgis-core-utilities.instructions.md +0 -247
- package/contexts/4.34/copilot/arcgis-editing.instructions.md +0 -262
- package/contexts/4.34/copilot/arcgis-geometry.instructions.md +0 -225
- package/contexts/4.34/copilot/arcgis-layers.instructions.md +0 -278
- package/contexts/4.34/copilot/arcgis-popup-templates.instructions.md +0 -266
- package/contexts/4.34/copilot/arcgis-portal-advanced.instructions.md +0 -275
- package/contexts/4.34/copilot/arcgis-smart-mapping.instructions.md +0 -184
- package/contexts/4.34/copilot/arcgis-time-animation.instructions.md +0 -112
- package/contexts/4.34/copilot/arcgis-visualization.instructions.md +0 -321
- package/contexts/4.34/copilot/arcgis-widgets-ui.instructions.md +0 -277
- /package/contexts/4.34/{claude → skills}/arcgis-arcade/SKILL.md +0 -0
- /package/contexts/4.34/{claude → skills}/arcgis-popup-templates/SKILL.md +0 -0
|
@@ -1,582 +1,582 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: arcgis-knowledge-graphs
|
|
3
|
-
description: Work with ArcGIS Knowledge graphs for storing and querying connected data. Use for graph databases, relationship visualization, and openCypher queries.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ArcGIS Knowledge Graphs
|
|
7
|
-
|
|
8
|
-
Use this skill for working with knowledge graphs, graph queries, and relationship visualization.
|
|
9
|
-
|
|
10
|
-
## Knowledge Graph Service
|
|
11
|
-
|
|
12
|
-
### Fetch Knowledge Graph
|
|
13
|
-
```javascript
|
|
14
|
-
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
15
|
-
|
|
16
|
-
const url = "https://your-server/server/rest/services/Hosted/YourKG/KnowledgeGraphServer";
|
|
17
|
-
const knowledgeGraph = await KGModule.fetchKnowledgeGraph(url);
|
|
18
|
-
|
|
19
|
-
console.log("Graph name:", knowledgeGraph.name);
|
|
20
|
-
console.log("Entity types:", knowledgeGraph.dataModel.entityTypes);
|
|
21
|
-
console.log("Relationship types:", knowledgeGraph.dataModel.relationshipTypes);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## KnowledgeGraphLayer
|
|
25
|
-
|
|
26
|
-
### Add to Map
|
|
27
|
-
```javascript
|
|
28
|
-
import KnowledgeGraphLayer from "@arcgis/core/layers/KnowledgeGraphLayer.js";
|
|
29
|
-
|
|
30
|
-
const kgLayer = new KnowledgeGraphLayer({
|
|
31
|
-
url: "https://your-server/server/rest/services/Hosted/YourKG/KnowledgeGraphServer"
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
await kgLayer.load();
|
|
35
|
-
map.add(kgLayer);
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
### Configure Sublayers
|
|
39
|
-
```javascript
|
|
40
|
-
const kgLayer = new KnowledgeGraphLayer({
|
|
41
|
-
url: "...",
|
|
42
|
-
// Only include specific entity types
|
|
43
|
-
inclusionModeDefinition: {
|
|
44
|
-
generateAllSublayers: false,
|
|
45
|
-
namedTypeDefinitions: new Map([
|
|
46
|
-
["Person", { useAllData: true }],
|
|
47
|
-
["Location", { useAllData: true }]
|
|
48
|
-
])
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Querying with openCypher
|
|
54
|
-
|
|
55
|
-
### Basic Query
|
|
56
|
-
```javascript
|
|
57
|
-
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
58
|
-
|
|
59
|
-
const result = await KGModule.executeQuery(knowledgeGraph, {
|
|
60
|
-
openCypherQuery: "MATCH (n:Person) RETURN n LIMIT 10"
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
console.log("Results:", result.resultRows);
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Streaming Query (Large Results)
|
|
67
|
-
```javascript
|
|
68
|
-
const queryResults = await KGModule.executeQueryStreaming(knowledgeGraph, {
|
|
69
|
-
openCypherQuery: "MATCH (n:Person)-[r]->(m) RETURN n, r, m"
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// Read stream
|
|
73
|
-
const reader = queryResults.resultRowsStream.getReader();
|
|
74
|
-
|
|
75
|
-
while (true) {
|
|
76
|
-
const { done, value } = await reader.read();
|
|
77
|
-
if (done) break;
|
|
78
|
-
|
|
79
|
-
// Process chunk
|
|
80
|
-
value.forEach(row => {
|
|
81
|
-
console.log("Row:", row);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Spatial Query with Bind Parameters
|
|
87
|
-
```javascript
|
|
88
|
-
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
89
|
-
import Polygon from "@arcgis/core/geometry/Polygon.js";
|
|
90
|
-
|
|
91
|
-
// Create geometry for spatial filter
|
|
92
|
-
const searchArea = new Polygon({
|
|
93
|
-
rings: [[
|
|
94
|
-
[-76, 45],
|
|
95
|
-
[-70, 45],
|
|
96
|
-
[-70, 40],
|
|
97
|
-
[-76, 40],
|
|
98
|
-
[-76, 45]
|
|
99
|
-
]]
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const queryResults = await KGModule.executeQueryStreaming(knowledgeGraph, {
|
|
103
|
-
openCypherQuery: `
|
|
104
|
-
MATCH path=(a:User)-[]->(b:Observation)
|
|
105
|
-
WHERE esri.graph.ST_Intersects($geometry, b.shape)
|
|
106
|
-
RETURN path
|
|
107
|
-
`,
|
|
108
|
-
bindParameters: {
|
|
109
|
-
geometry: searchArea
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Query with Filters
|
|
115
|
-
```javascript
|
|
116
|
-
// Filter by property
|
|
117
|
-
const result = await KGModule.executeQuery(knowledgeGraph, {
|
|
118
|
-
openCypherQuery: `
|
|
119
|
-
MATCH (p:Person)
|
|
120
|
-
WHERE p.age > 30 AND p.name CONTAINS 'John'
|
|
121
|
-
RETURN p
|
|
122
|
-
`
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
// Query relationships
|
|
126
|
-
const result = await KGModule.executeQuery(knowledgeGraph, {
|
|
127
|
-
openCypherQuery: `
|
|
128
|
-
MATCH (p:Person)-[r:WORKS_AT]->(c:Company)
|
|
129
|
-
WHERE c.name = 'Esri'
|
|
130
|
-
RETURN p.name, r.startDate, c.name
|
|
131
|
-
`
|
|
132
|
-
});
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
## Link Chart Visualization
|
|
136
|
-
|
|
137
|
-
### Create Link Chart
|
|
138
|
-
```javascript
|
|
139
|
-
import WebLinkChart from "@arcgis/core/WebLinkChart.js";
|
|
140
|
-
import LinkChartView from "@arcgis/core/views/LinkChartView.js";
|
|
141
|
-
import LinkChartLayer from "@arcgis/core/layers/LinkChartLayer.js";
|
|
142
|
-
|
|
143
|
-
const linkChartLayer = new LinkChartLayer({
|
|
144
|
-
url: "https://your-server/.../KnowledgeGraphServer"
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const linkChart = new WebLinkChart({
|
|
148
|
-
layers: [linkChartLayer]
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
const linkChartView = new LinkChartView({
|
|
152
|
-
container: "linkChartDiv",
|
|
153
|
-
map: linkChart
|
|
154
|
-
});
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### LinkChartView Configuration
|
|
158
|
-
|
|
159
|
-
```javascript
|
|
160
|
-
const linkChartView = new LinkChartView({
|
|
161
|
-
container: "linkChartDiv",
|
|
162
|
-
map: linkChart,
|
|
163
|
-
|
|
164
|
-
// Enable interaction
|
|
165
|
-
highlightOptions: {
|
|
166
|
-
color: [0, 255, 255, 1],
|
|
167
|
-
haloColor: [0, 255, 255, 0.5],
|
|
168
|
-
haloOpacity: 0.8
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
// Navigation
|
|
172
|
-
navigation: {
|
|
173
|
-
mouseWheelZoomEnabled: true,
|
|
174
|
-
browserTouchPanEnabled: true
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// View events
|
|
179
|
-
linkChartView.on("click", async (event) => {
|
|
180
|
-
const response = await linkChartView.hitTest(event);
|
|
181
|
-
if (response.results.length > 0) {
|
|
182
|
-
const graphic = response.results[0].graphic;
|
|
183
|
-
console.log("Clicked:", graphic.attributes);
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// Watch for selection changes
|
|
188
|
-
linkChartView.on("selection-change", (event) => {
|
|
189
|
-
console.log("Selected entities:", event.added);
|
|
190
|
-
console.log("Deselected entities:", event.removed);
|
|
191
|
-
});
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Link Chart Component
|
|
195
|
-
```html
|
|
196
|
-
<arcgis-link-chart>
|
|
197
|
-
<arcgis-legend slot="top-right"></arcgis-legend>
|
|
198
|
-
<arcgis-zoom slot="bottom-right"></arcgis-zoom>
|
|
199
|
-
</arcgis-link-chart>
|
|
200
|
-
|
|
201
|
-
<script type="module">
|
|
202
|
-
const linkChartComponent = document.querySelector("arcgis-link-chart");
|
|
203
|
-
await linkChartComponent.componentOnReady();
|
|
204
|
-
|
|
205
|
-
const lcView = linkChartComponent.view;
|
|
206
|
-
const linkChart = lcView.map;
|
|
207
|
-
|
|
208
|
-
// Add records to link chart
|
|
209
|
-
linkChart.addRecords([
|
|
210
|
-
{ id: "entity1", typeName: "Person" },
|
|
211
|
-
{ id: "entity2", typeName: "Company" }
|
|
212
|
-
]);
|
|
213
|
-
</script>
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
### Link Chart Layout Settings
|
|
217
|
-
|
|
218
|
-
```javascript
|
|
219
|
-
// Access layout settings
|
|
220
|
-
const layoutSettings = linkChart.layoutSettings;
|
|
221
|
-
|
|
222
|
-
// Organic Layout (default)
|
|
223
|
-
linkChart.layoutSettings = {
|
|
224
|
-
type: "organic",
|
|
225
|
-
avoidLabelOverlap: true,
|
|
226
|
-
compactness: 0.5, // 0-1, how tightly packed
|
|
227
|
-
orientation: "top-to-bottom" // top-to-bottom, bottom-to-top, left-to-right, right-to-left
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
// Chronological Layout
|
|
231
|
-
linkChart.layoutSettings = {
|
|
232
|
-
type: "chronological",
|
|
233
|
-
dateField: "timestamp",
|
|
234
|
-
groupByField: "category",
|
|
235
|
-
orientation: "horizontal", // horizontal, vertical
|
|
236
|
-
showTimeline: true
|
|
237
|
-
};
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### OrganicLayoutSettings
|
|
241
|
-
|
|
242
|
-
```javascript
|
|
243
|
-
import OrganicLayoutSettings from "@arcgis/core/webdoc/applicationProperties/OrganicLayoutSettings.js";
|
|
244
|
-
|
|
245
|
-
const organicLayout = new OrganicLayoutSettings({
|
|
246
|
-
avoidLabelOverlap: true,
|
|
247
|
-
compactness: 0.6,
|
|
248
|
-
componentLayoutEnabled: true,
|
|
249
|
-
deterministic: true,
|
|
250
|
-
minimumNodeDistance: 50,
|
|
251
|
-
orientation: "top-to-bottom",
|
|
252
|
-
preferredEdgeLength: 100,
|
|
253
|
-
starSubstructureEnabled: true,
|
|
254
|
-
treeSubstructureEnabled: true
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
linkChart.layoutSettings = organicLayout;
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### ChronologicalLayoutSettings
|
|
261
|
-
|
|
262
|
-
```javascript
|
|
263
|
-
import ChronologicalLayoutSettings from "@arcgis/core/webdoc/applicationProperties/ChronologicalLayoutSettings.js";
|
|
264
|
-
|
|
265
|
-
const chronoLayout = new ChronologicalLayoutSettings({
|
|
266
|
-
dateField: "event_date",
|
|
267
|
-
groupByField: "event_type",
|
|
268
|
-
orientation: "horizontal",
|
|
269
|
-
showTimeline: true,
|
|
270
|
-
timelinePosition: "bottom",
|
|
271
|
-
sortOrder: "ascending" // ascending, descending
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
linkChart.layoutSettings = chronoLayout;
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
### LinkChartLayoutSwitcher Widget
|
|
278
|
-
|
|
279
|
-
```javascript
|
|
280
|
-
import LinkChartLayoutSwitcher from "@arcgis/core/widgets/LinkChartLayoutSwitcher.js";
|
|
281
|
-
|
|
282
|
-
const layoutSwitcher = new LinkChartLayoutSwitcher({
|
|
283
|
-
view: linkChartView,
|
|
284
|
-
layouts: [
|
|
285
|
-
{
|
|
286
|
-
name: "Organic",
|
|
287
|
-
settings: new OrganicLayoutSettings({ compactness: 0.5 })
|
|
288
|
-
},
|
|
289
|
-
{
|
|
290
|
-
name: "Timeline",
|
|
291
|
-
settings: new ChronologicalLayoutSettings({ dateField: "date" })
|
|
292
|
-
}
|
|
293
|
-
]
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
linkChartView.ui.add(layoutSwitcher, "top-right");
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
### Non-Spatial Data Display
|
|
300
|
-
|
|
301
|
-
```javascript
|
|
302
|
-
// Configure non-spatial display for entities
|
|
303
|
-
const linkChartLayer = new LinkChartLayer({
|
|
304
|
-
url: "...",
|
|
305
|
-
nonspatialDataDisplay: {
|
|
306
|
-
entityTypes: {
|
|
307
|
-
Person: {
|
|
308
|
-
displayField: "name",
|
|
309
|
-
symbol: {
|
|
310
|
-
type: "simple-marker",
|
|
311
|
-
color: "blue",
|
|
312
|
-
size: 20
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
Company: {
|
|
316
|
-
displayField: "company_name",
|
|
317
|
-
symbol: {
|
|
318
|
-
type: "simple-marker",
|
|
319
|
-
color: "green",
|
|
320
|
-
size: 25
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
relationshipTypes: {
|
|
325
|
-
WORKS_AT: {
|
|
326
|
-
symbol: {
|
|
327
|
-
type: "simple-line",
|
|
328
|
-
color: "gray",
|
|
329
|
-
width: 2
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Adding and Removing Records
|
|
338
|
-
|
|
339
|
-
```javascript
|
|
340
|
-
// Add records
|
|
341
|
-
await linkChart.addRecords([
|
|
342
|
-
{ id: "person-1", typeName: "Person" },
|
|
343
|
-
{ id: "company-1", typeName: "Company" },
|
|
344
|
-
{ id: "rel-1", typeName: "WORKS_AT" }
|
|
345
|
-
]);
|
|
346
|
-
|
|
347
|
-
// Remove records
|
|
348
|
-
await linkChart.removeRecords([
|
|
349
|
-
{ id: "person-1", typeName: "Person" }
|
|
350
|
-
]);
|
|
351
|
-
|
|
352
|
-
// Clear all records
|
|
353
|
-
await linkChart.removeAllRecords();
|
|
354
|
-
|
|
355
|
-
// Get current records
|
|
356
|
-
const records = linkChart.records;
|
|
357
|
-
console.log("Current entities:", records.entities);
|
|
358
|
-
console.log("Current relationships:", records.relationships);
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
### Update Link Chart from Query Results
|
|
362
|
-
```javascript
|
|
363
|
-
async function updateLinkChart(queryResults, linkChart) {
|
|
364
|
-
const reader = queryResults.resultRowsStream.getReader();
|
|
365
|
-
|
|
366
|
-
while (true) {
|
|
367
|
-
const { done, value } = await reader.read();
|
|
368
|
-
if (done) break;
|
|
369
|
-
|
|
370
|
-
const records = [];
|
|
371
|
-
for (const row of value) {
|
|
372
|
-
for (const record of row[0].path) {
|
|
373
|
-
records.push({
|
|
374
|
-
id: record.id,
|
|
375
|
-
typeName: record.typeName
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
linkChart.addRecords(records);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
### Expand/Collapse Entities
|
|
386
|
-
|
|
387
|
-
```javascript
|
|
388
|
-
// Expand entity to show connections
|
|
389
|
-
await linkChart.expand({
|
|
390
|
-
ids: ["entity-id"],
|
|
391
|
-
typeName: "Person",
|
|
392
|
-
relationshipTypes: ["KNOWS", "WORKS_AT"],
|
|
393
|
-
direction: "both" // outgoing, incoming, both
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
// Collapse entity
|
|
397
|
-
await linkChart.collapse({
|
|
398
|
-
ids: ["entity-id"],
|
|
399
|
-
typeName: "Person"
|
|
400
|
-
});
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Selection and Highlighting
|
|
404
|
-
|
|
405
|
-
```javascript
|
|
406
|
-
// Select entities programmatically
|
|
407
|
-
linkChartView.select([
|
|
408
|
-
{ id: "person-1", typeName: "Person" },
|
|
409
|
-
{ id: "person-2", typeName: "Person" }
|
|
410
|
-
]);
|
|
411
|
-
|
|
412
|
-
// Clear selection
|
|
413
|
-
linkChartView.clearSelection();
|
|
414
|
-
|
|
415
|
-
// Highlight (temporary visual emphasis)
|
|
416
|
-
const highlightHandle = linkChartView.highlight([
|
|
417
|
-
{ id: "person-1", typeName: "Person" }
|
|
418
|
-
]);
|
|
419
|
-
|
|
420
|
-
// Remove highlight
|
|
421
|
-
highlightHandle.remove();
|
|
422
|
-
|
|
423
|
-
// Go to specific entities
|
|
424
|
-
linkChartView.goTo([
|
|
425
|
-
{ id: "person-1", typeName: "Person" }
|
|
426
|
-
]);
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
### WebLinkChart Properties
|
|
430
|
-
|
|
431
|
-
```javascript
|
|
432
|
-
import WebLinkChart from "@arcgis/core/WebLinkChart.js";
|
|
433
|
-
|
|
434
|
-
const webLinkChart = new WebLinkChart({
|
|
435
|
-
// Portal item (load existing)
|
|
436
|
-
portalItem: { id: "LINKCHART_ID" },
|
|
437
|
-
|
|
438
|
-
// Or create from scratch
|
|
439
|
-
layers: [linkChartLayer],
|
|
440
|
-
|
|
441
|
-
// Layout settings
|
|
442
|
-
layoutSettings: organicLayout,
|
|
443
|
-
|
|
444
|
-
// Initial records
|
|
445
|
-
initialRecords: {
|
|
446
|
-
entities: [
|
|
447
|
-
{ id: "entity-1", typeName: "Person" }
|
|
448
|
-
],
|
|
449
|
-
relationships: []
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
|
-
|
|
453
|
-
// Save to portal
|
|
454
|
-
await webLinkChart.saveAs({
|
|
455
|
-
title: "My Link Chart",
|
|
456
|
-
snippet: "Visualization of entity relationships"
|
|
457
|
-
});
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
## Search Knowledge Graph
|
|
461
|
-
|
|
462
|
-
```javascript
|
|
463
|
-
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
464
|
-
|
|
465
|
-
const searchResults = await KGModule.executeSearch(knowledgeGraph, {
|
|
466
|
-
searchQuery: "John Smith",
|
|
467
|
-
typeCategoryFilter: "entity", // or "relationship", "both"
|
|
468
|
-
typeNames: ["Person", "Employee"],
|
|
469
|
-
returnSearchContext: true
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
searchResults.results.forEach(result => {
|
|
473
|
-
console.log("Found:", result.typeName, result.id);
|
|
474
|
-
console.log("Context:", result.searchContext);
|
|
475
|
-
});
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
## Apply Edits
|
|
479
|
-
|
|
480
|
-
```javascript
|
|
481
|
-
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
482
|
-
|
|
483
|
-
// Add entity
|
|
484
|
-
const addResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
485
|
-
entityAdds: [{
|
|
486
|
-
typeName: "Person",
|
|
487
|
-
properties: {
|
|
488
|
-
name: "Jane Doe",
|
|
489
|
-
age: 28
|
|
490
|
-
}
|
|
491
|
-
}]
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
// Update entity
|
|
495
|
-
const updateResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
496
|
-
entityUpdates: [{
|
|
497
|
-
typeName: "Person",
|
|
498
|
-
properties: {
|
|
499
|
-
globalId: "{existing-global-id}",
|
|
500
|
-
age: 29
|
|
501
|
-
}
|
|
502
|
-
}]
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
// Delete entity
|
|
506
|
-
const deleteResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
507
|
-
entityDeletes: [{
|
|
508
|
-
typeName: "Person",
|
|
509
|
-
ids: ["{global-id-to-delete}"]
|
|
510
|
-
}]
|
|
511
|
-
});
|
|
512
|
-
|
|
513
|
-
// Add relationship
|
|
514
|
-
const relResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
515
|
-
relationshipAdds: [{
|
|
516
|
-
typeName: "WORKS_AT",
|
|
517
|
-
properties: {
|
|
518
|
-
originGlobalId: "{person-global-id}",
|
|
519
|
-
destinationGlobalId: "{company-global-id}",
|
|
520
|
-
startDate: new Date()
|
|
521
|
-
}
|
|
522
|
-
}]
|
|
523
|
-
});
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
## Data Model
|
|
527
|
-
|
|
528
|
-
```javascript
|
|
529
|
-
// Access data model
|
|
530
|
-
const dataModel = knowledgeGraph.dataModel;
|
|
531
|
-
|
|
532
|
-
// Entity types
|
|
533
|
-
dataModel.entityTypes.forEach(entityType => {
|
|
534
|
-
console.log("Entity:", entityType.name);
|
|
535
|
-
console.log("Properties:", entityType.properties);
|
|
536
|
-
});
|
|
537
|
-
|
|
538
|
-
// Relationship types
|
|
539
|
-
dataModel.relationshipTypes.forEach(relType => {
|
|
540
|
-
console.log("Relationship:", relType.name);
|
|
541
|
-
console.log("Origin:", relType.originEntityTypes);
|
|
542
|
-
console.log("Destination:", relType.destinationEntityTypes);
|
|
543
|
-
});
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
## Common openCypher Patterns
|
|
547
|
-
|
|
548
|
-
```cypher
|
|
549
|
-
-- Find all entities
|
|
550
|
-
MATCH (n) RETURN n
|
|
551
|
-
|
|
552
|
-
-- Find specific type
|
|
553
|
-
MATCH (p:Person) RETURN p
|
|
554
|
-
|
|
555
|
-
-- Find relationships
|
|
556
|
-
MATCH (a)-[r]->(b) RETURN a, r, b
|
|
557
|
-
|
|
558
|
-
-- Find path
|
|
559
|
-
MATCH path = (a:Person)-[:KNOWS*1..3]->(b:Person)
|
|
560
|
-
WHERE a.name = 'John'
|
|
561
|
-
RETURN path
|
|
562
|
-
|
|
563
|
-
-- Aggregate
|
|
564
|
-
MATCH (p:Person)-[:WORKS_AT]->(c:Company)
|
|
565
|
-
RETURN c.name, COUNT(p) as employeeCount
|
|
566
|
-
|
|
567
|
-
-- Spatial filter
|
|
568
|
-
MATCH (loc:Location)
|
|
569
|
-
WHERE esri.graph.ST_Intersects($geometry, loc.shape)
|
|
570
|
-
RETURN loc
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
## Common Pitfalls
|
|
574
|
-
|
|
575
|
-
1. **Authentication required**: Knowledge graph services typically require authentication
|
|
576
|
-
|
|
577
|
-
2. **Streaming for large results**: Use `executeQueryStreaming` for queries that may return many results
|
|
578
|
-
|
|
579
|
-
3. **Geometry conversion**: Convert geometries to WGS84 before using in spatial queries
|
|
580
|
-
|
|
581
|
-
4. **Case sensitivity**: openCypher property names are case-sensitive
|
|
582
|
-
|
|
1
|
+
---
|
|
2
|
+
name: arcgis-knowledge-graphs
|
|
3
|
+
description: Work with ArcGIS Knowledge graphs for storing and querying connected data. Use for graph databases, relationship visualization, and openCypher queries.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ArcGIS Knowledge Graphs
|
|
7
|
+
|
|
8
|
+
Use this skill for working with knowledge graphs, graph queries, and relationship visualization.
|
|
9
|
+
|
|
10
|
+
## Knowledge Graph Service
|
|
11
|
+
|
|
12
|
+
### Fetch Knowledge Graph
|
|
13
|
+
```javascript
|
|
14
|
+
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
15
|
+
|
|
16
|
+
const url = "https://your-server/server/rest/services/Hosted/YourKG/KnowledgeGraphServer";
|
|
17
|
+
const knowledgeGraph = await KGModule.fetchKnowledgeGraph(url);
|
|
18
|
+
|
|
19
|
+
console.log("Graph name:", knowledgeGraph.name);
|
|
20
|
+
console.log("Entity types:", knowledgeGraph.dataModel.entityTypes);
|
|
21
|
+
console.log("Relationship types:", knowledgeGraph.dataModel.relationshipTypes);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## KnowledgeGraphLayer
|
|
25
|
+
|
|
26
|
+
### Add to Map
|
|
27
|
+
```javascript
|
|
28
|
+
import KnowledgeGraphLayer from "@arcgis/core/layers/KnowledgeGraphLayer.js";
|
|
29
|
+
|
|
30
|
+
const kgLayer = new KnowledgeGraphLayer({
|
|
31
|
+
url: "https://your-server/server/rest/services/Hosted/YourKG/KnowledgeGraphServer"
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
await kgLayer.load();
|
|
35
|
+
map.add(kgLayer);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Configure Sublayers
|
|
39
|
+
```javascript
|
|
40
|
+
const kgLayer = new KnowledgeGraphLayer({
|
|
41
|
+
url: "...",
|
|
42
|
+
// Only include specific entity types
|
|
43
|
+
inclusionModeDefinition: {
|
|
44
|
+
generateAllSublayers: false,
|
|
45
|
+
namedTypeDefinitions: new Map([
|
|
46
|
+
["Person", { useAllData: true }],
|
|
47
|
+
["Location", { useAllData: true }]
|
|
48
|
+
])
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Querying with openCypher
|
|
54
|
+
|
|
55
|
+
### Basic Query
|
|
56
|
+
```javascript
|
|
57
|
+
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
58
|
+
|
|
59
|
+
const result = await KGModule.executeQuery(knowledgeGraph, {
|
|
60
|
+
openCypherQuery: "MATCH (n:Person) RETURN n LIMIT 10"
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
console.log("Results:", result.resultRows);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Streaming Query (Large Results)
|
|
67
|
+
```javascript
|
|
68
|
+
const queryResults = await KGModule.executeQueryStreaming(knowledgeGraph, {
|
|
69
|
+
openCypherQuery: "MATCH (n:Person)-[r]->(m) RETURN n, r, m"
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Read stream
|
|
73
|
+
const reader = queryResults.resultRowsStream.getReader();
|
|
74
|
+
|
|
75
|
+
while (true) {
|
|
76
|
+
const { done, value } = await reader.read();
|
|
77
|
+
if (done) break;
|
|
78
|
+
|
|
79
|
+
// Process chunk
|
|
80
|
+
value.forEach(row => {
|
|
81
|
+
console.log("Row:", row);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Spatial Query with Bind Parameters
|
|
87
|
+
```javascript
|
|
88
|
+
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
89
|
+
import Polygon from "@arcgis/core/geometry/Polygon.js";
|
|
90
|
+
|
|
91
|
+
// Create geometry for spatial filter
|
|
92
|
+
const searchArea = new Polygon({
|
|
93
|
+
rings: [[
|
|
94
|
+
[-76, 45],
|
|
95
|
+
[-70, 45],
|
|
96
|
+
[-70, 40],
|
|
97
|
+
[-76, 40],
|
|
98
|
+
[-76, 45]
|
|
99
|
+
]]
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const queryResults = await KGModule.executeQueryStreaming(knowledgeGraph, {
|
|
103
|
+
openCypherQuery: `
|
|
104
|
+
MATCH path=(a:User)-[]->(b:Observation)
|
|
105
|
+
WHERE esri.graph.ST_Intersects($geometry, b.shape)
|
|
106
|
+
RETURN path
|
|
107
|
+
`,
|
|
108
|
+
bindParameters: {
|
|
109
|
+
geometry: searchArea
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Query with Filters
|
|
115
|
+
```javascript
|
|
116
|
+
// Filter by property
|
|
117
|
+
const result = await KGModule.executeQuery(knowledgeGraph, {
|
|
118
|
+
openCypherQuery: `
|
|
119
|
+
MATCH (p:Person)
|
|
120
|
+
WHERE p.age > 30 AND p.name CONTAINS 'John'
|
|
121
|
+
RETURN p
|
|
122
|
+
`
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Query relationships
|
|
126
|
+
const result = await KGModule.executeQuery(knowledgeGraph, {
|
|
127
|
+
openCypherQuery: `
|
|
128
|
+
MATCH (p:Person)-[r:WORKS_AT]->(c:Company)
|
|
129
|
+
WHERE c.name = 'Esri'
|
|
130
|
+
RETURN p.name, r.startDate, c.name
|
|
131
|
+
`
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Link Chart Visualization
|
|
136
|
+
|
|
137
|
+
### Create Link Chart
|
|
138
|
+
```javascript
|
|
139
|
+
import WebLinkChart from "@arcgis/core/WebLinkChart.js";
|
|
140
|
+
import LinkChartView from "@arcgis/core/views/LinkChartView.js";
|
|
141
|
+
import LinkChartLayer from "@arcgis/core/layers/LinkChartLayer.js";
|
|
142
|
+
|
|
143
|
+
const linkChartLayer = new LinkChartLayer({
|
|
144
|
+
url: "https://your-server/.../KnowledgeGraphServer"
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const linkChart = new WebLinkChart({
|
|
148
|
+
layers: [linkChartLayer]
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const linkChartView = new LinkChartView({
|
|
152
|
+
container: "linkChartDiv",
|
|
153
|
+
map: linkChart
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### LinkChartView Configuration
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
const linkChartView = new LinkChartView({
|
|
161
|
+
container: "linkChartDiv",
|
|
162
|
+
map: linkChart,
|
|
163
|
+
|
|
164
|
+
// Enable interaction
|
|
165
|
+
highlightOptions: {
|
|
166
|
+
color: [0, 255, 255, 1],
|
|
167
|
+
haloColor: [0, 255, 255, 0.5],
|
|
168
|
+
haloOpacity: 0.8
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Navigation
|
|
172
|
+
navigation: {
|
|
173
|
+
mouseWheelZoomEnabled: true,
|
|
174
|
+
browserTouchPanEnabled: true
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// View events
|
|
179
|
+
linkChartView.on("click", async (event) => {
|
|
180
|
+
const response = await linkChartView.hitTest(event);
|
|
181
|
+
if (response.results.length > 0) {
|
|
182
|
+
const graphic = response.results[0].graphic;
|
|
183
|
+
console.log("Clicked:", graphic.attributes);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Watch for selection changes
|
|
188
|
+
linkChartView.on("selection-change", (event) => {
|
|
189
|
+
console.log("Selected entities:", event.added);
|
|
190
|
+
console.log("Deselected entities:", event.removed);
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Link Chart Component
|
|
195
|
+
```html
|
|
196
|
+
<arcgis-link-chart>
|
|
197
|
+
<arcgis-legend slot="top-right"></arcgis-legend>
|
|
198
|
+
<arcgis-zoom slot="bottom-right"></arcgis-zoom>
|
|
199
|
+
</arcgis-link-chart>
|
|
200
|
+
|
|
201
|
+
<script type="module">
|
|
202
|
+
const linkChartComponent = document.querySelector("arcgis-link-chart");
|
|
203
|
+
await linkChartComponent.componentOnReady();
|
|
204
|
+
|
|
205
|
+
const lcView = linkChartComponent.view;
|
|
206
|
+
const linkChart = lcView.map;
|
|
207
|
+
|
|
208
|
+
// Add records to link chart
|
|
209
|
+
linkChart.addRecords([
|
|
210
|
+
{ id: "entity1", typeName: "Person" },
|
|
211
|
+
{ id: "entity2", typeName: "Company" }
|
|
212
|
+
]);
|
|
213
|
+
</script>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Link Chart Layout Settings
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// Access layout settings
|
|
220
|
+
const layoutSettings = linkChart.layoutSettings;
|
|
221
|
+
|
|
222
|
+
// Organic Layout (default)
|
|
223
|
+
linkChart.layoutSettings = {
|
|
224
|
+
type: "organic",
|
|
225
|
+
avoidLabelOverlap: true,
|
|
226
|
+
compactness: 0.5, // 0-1, how tightly packed
|
|
227
|
+
orientation: "top-to-bottom" // top-to-bottom, bottom-to-top, left-to-right, right-to-left
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Chronological Layout
|
|
231
|
+
linkChart.layoutSettings = {
|
|
232
|
+
type: "chronological",
|
|
233
|
+
dateField: "timestamp",
|
|
234
|
+
groupByField: "category",
|
|
235
|
+
orientation: "horizontal", // horizontal, vertical
|
|
236
|
+
showTimeline: true
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### OrganicLayoutSettings
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
import OrganicLayoutSettings from "@arcgis/core/webdoc/applicationProperties/OrganicLayoutSettings.js";
|
|
244
|
+
|
|
245
|
+
const organicLayout = new OrganicLayoutSettings({
|
|
246
|
+
avoidLabelOverlap: true,
|
|
247
|
+
compactness: 0.6,
|
|
248
|
+
componentLayoutEnabled: true,
|
|
249
|
+
deterministic: true,
|
|
250
|
+
minimumNodeDistance: 50,
|
|
251
|
+
orientation: "top-to-bottom",
|
|
252
|
+
preferredEdgeLength: 100,
|
|
253
|
+
starSubstructureEnabled: true,
|
|
254
|
+
treeSubstructureEnabled: true
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
linkChart.layoutSettings = organicLayout;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### ChronologicalLayoutSettings
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
import ChronologicalLayoutSettings from "@arcgis/core/webdoc/applicationProperties/ChronologicalLayoutSettings.js";
|
|
264
|
+
|
|
265
|
+
const chronoLayout = new ChronologicalLayoutSettings({
|
|
266
|
+
dateField: "event_date",
|
|
267
|
+
groupByField: "event_type",
|
|
268
|
+
orientation: "horizontal",
|
|
269
|
+
showTimeline: true,
|
|
270
|
+
timelinePosition: "bottom",
|
|
271
|
+
sortOrder: "ascending" // ascending, descending
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
linkChart.layoutSettings = chronoLayout;
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### LinkChartLayoutSwitcher Widget
|
|
278
|
+
|
|
279
|
+
```javascript
|
|
280
|
+
import LinkChartLayoutSwitcher from "@arcgis/core/widgets/LinkChartLayoutSwitcher.js";
|
|
281
|
+
|
|
282
|
+
const layoutSwitcher = new LinkChartLayoutSwitcher({
|
|
283
|
+
view: linkChartView,
|
|
284
|
+
layouts: [
|
|
285
|
+
{
|
|
286
|
+
name: "Organic",
|
|
287
|
+
settings: new OrganicLayoutSettings({ compactness: 0.5 })
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
name: "Timeline",
|
|
291
|
+
settings: new ChronologicalLayoutSettings({ dateField: "date" })
|
|
292
|
+
}
|
|
293
|
+
]
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
linkChartView.ui.add(layoutSwitcher, "top-right");
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Non-Spatial Data Display
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
// Configure non-spatial display for entities
|
|
303
|
+
const linkChartLayer = new LinkChartLayer({
|
|
304
|
+
url: "...",
|
|
305
|
+
nonspatialDataDisplay: {
|
|
306
|
+
entityTypes: {
|
|
307
|
+
Person: {
|
|
308
|
+
displayField: "name",
|
|
309
|
+
symbol: {
|
|
310
|
+
type: "simple-marker",
|
|
311
|
+
color: "blue",
|
|
312
|
+
size: 20
|
|
313
|
+
}
|
|
314
|
+
},
|
|
315
|
+
Company: {
|
|
316
|
+
displayField: "company_name",
|
|
317
|
+
symbol: {
|
|
318
|
+
type: "simple-marker",
|
|
319
|
+
color: "green",
|
|
320
|
+
size: 25
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
relationshipTypes: {
|
|
325
|
+
WORKS_AT: {
|
|
326
|
+
symbol: {
|
|
327
|
+
type: "simple-line",
|
|
328
|
+
color: "gray",
|
|
329
|
+
width: 2
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Adding and Removing Records
|
|
338
|
+
|
|
339
|
+
```javascript
|
|
340
|
+
// Add records
|
|
341
|
+
await linkChart.addRecords([
|
|
342
|
+
{ id: "person-1", typeName: "Person" },
|
|
343
|
+
{ id: "company-1", typeName: "Company" },
|
|
344
|
+
{ id: "rel-1", typeName: "WORKS_AT" }
|
|
345
|
+
]);
|
|
346
|
+
|
|
347
|
+
// Remove records
|
|
348
|
+
await linkChart.removeRecords([
|
|
349
|
+
{ id: "person-1", typeName: "Person" }
|
|
350
|
+
]);
|
|
351
|
+
|
|
352
|
+
// Clear all records
|
|
353
|
+
await linkChart.removeAllRecords();
|
|
354
|
+
|
|
355
|
+
// Get current records
|
|
356
|
+
const records = linkChart.records;
|
|
357
|
+
console.log("Current entities:", records.entities);
|
|
358
|
+
console.log("Current relationships:", records.relationships);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Update Link Chart from Query Results
|
|
362
|
+
```javascript
|
|
363
|
+
async function updateLinkChart(queryResults, linkChart) {
|
|
364
|
+
const reader = queryResults.resultRowsStream.getReader();
|
|
365
|
+
|
|
366
|
+
while (true) {
|
|
367
|
+
const { done, value } = await reader.read();
|
|
368
|
+
if (done) break;
|
|
369
|
+
|
|
370
|
+
const records = [];
|
|
371
|
+
for (const row of value) {
|
|
372
|
+
for (const record of row[0].path) {
|
|
373
|
+
records.push({
|
|
374
|
+
id: record.id,
|
|
375
|
+
typeName: record.typeName
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
linkChart.addRecords(records);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Expand/Collapse Entities
|
|
386
|
+
|
|
387
|
+
```javascript
|
|
388
|
+
// Expand entity to show connections
|
|
389
|
+
await linkChart.expand({
|
|
390
|
+
ids: ["entity-id"],
|
|
391
|
+
typeName: "Person",
|
|
392
|
+
relationshipTypes: ["KNOWS", "WORKS_AT"],
|
|
393
|
+
direction: "both" // outgoing, incoming, both
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Collapse entity
|
|
397
|
+
await linkChart.collapse({
|
|
398
|
+
ids: ["entity-id"],
|
|
399
|
+
typeName: "Person"
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Selection and Highlighting
|
|
404
|
+
|
|
405
|
+
```javascript
|
|
406
|
+
// Select entities programmatically
|
|
407
|
+
linkChartView.select([
|
|
408
|
+
{ id: "person-1", typeName: "Person" },
|
|
409
|
+
{ id: "person-2", typeName: "Person" }
|
|
410
|
+
]);
|
|
411
|
+
|
|
412
|
+
// Clear selection
|
|
413
|
+
linkChartView.clearSelection();
|
|
414
|
+
|
|
415
|
+
// Highlight (temporary visual emphasis)
|
|
416
|
+
const highlightHandle = linkChartView.highlight([
|
|
417
|
+
{ id: "person-1", typeName: "Person" }
|
|
418
|
+
]);
|
|
419
|
+
|
|
420
|
+
// Remove highlight
|
|
421
|
+
highlightHandle.remove();
|
|
422
|
+
|
|
423
|
+
// Go to specific entities
|
|
424
|
+
linkChartView.goTo([
|
|
425
|
+
{ id: "person-1", typeName: "Person" }
|
|
426
|
+
]);
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### WebLinkChart Properties
|
|
430
|
+
|
|
431
|
+
```javascript
|
|
432
|
+
import WebLinkChart from "@arcgis/core/WebLinkChart.js";
|
|
433
|
+
|
|
434
|
+
const webLinkChart = new WebLinkChart({
|
|
435
|
+
// Portal item (load existing)
|
|
436
|
+
portalItem: { id: "LINKCHART_ID" },
|
|
437
|
+
|
|
438
|
+
// Or create from scratch
|
|
439
|
+
layers: [linkChartLayer],
|
|
440
|
+
|
|
441
|
+
// Layout settings
|
|
442
|
+
layoutSettings: organicLayout,
|
|
443
|
+
|
|
444
|
+
// Initial records
|
|
445
|
+
initialRecords: {
|
|
446
|
+
entities: [
|
|
447
|
+
{ id: "entity-1", typeName: "Person" }
|
|
448
|
+
],
|
|
449
|
+
relationships: []
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// Save to portal
|
|
454
|
+
await webLinkChart.saveAs({
|
|
455
|
+
title: "My Link Chart",
|
|
456
|
+
snippet: "Visualization of entity relationships"
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Search Knowledge Graph
|
|
461
|
+
|
|
462
|
+
```javascript
|
|
463
|
+
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
464
|
+
|
|
465
|
+
const searchResults = await KGModule.executeSearch(knowledgeGraph, {
|
|
466
|
+
searchQuery: "John Smith",
|
|
467
|
+
typeCategoryFilter: "entity", // or "relationship", "both"
|
|
468
|
+
typeNames: ["Person", "Employee"],
|
|
469
|
+
returnSearchContext: true
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
searchResults.results.forEach(result => {
|
|
473
|
+
console.log("Found:", result.typeName, result.id);
|
|
474
|
+
console.log("Context:", result.searchContext);
|
|
475
|
+
});
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
## Apply Edits
|
|
479
|
+
|
|
480
|
+
```javascript
|
|
481
|
+
import KGModule from "@arcgis/core/rest/knowledgeGraphService.js";
|
|
482
|
+
|
|
483
|
+
// Add entity
|
|
484
|
+
const addResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
485
|
+
entityAdds: [{
|
|
486
|
+
typeName: "Person",
|
|
487
|
+
properties: {
|
|
488
|
+
name: "Jane Doe",
|
|
489
|
+
age: 28
|
|
490
|
+
}
|
|
491
|
+
}]
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
// Update entity
|
|
495
|
+
const updateResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
496
|
+
entityUpdates: [{
|
|
497
|
+
typeName: "Person",
|
|
498
|
+
properties: {
|
|
499
|
+
globalId: "{existing-global-id}",
|
|
500
|
+
age: 29
|
|
501
|
+
}
|
|
502
|
+
}]
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Delete entity
|
|
506
|
+
const deleteResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
507
|
+
entityDeletes: [{
|
|
508
|
+
typeName: "Person",
|
|
509
|
+
ids: ["{global-id-to-delete}"]
|
|
510
|
+
}]
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Add relationship
|
|
514
|
+
const relResult = await KGModule.executeApplyEdits(knowledgeGraph, {
|
|
515
|
+
relationshipAdds: [{
|
|
516
|
+
typeName: "WORKS_AT",
|
|
517
|
+
properties: {
|
|
518
|
+
originGlobalId: "{person-global-id}",
|
|
519
|
+
destinationGlobalId: "{company-global-id}",
|
|
520
|
+
startDate: new Date()
|
|
521
|
+
}
|
|
522
|
+
}]
|
|
523
|
+
});
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## Data Model
|
|
527
|
+
|
|
528
|
+
```javascript
|
|
529
|
+
// Access data model
|
|
530
|
+
const dataModel = knowledgeGraph.dataModel;
|
|
531
|
+
|
|
532
|
+
// Entity types
|
|
533
|
+
dataModel.entityTypes.forEach(entityType => {
|
|
534
|
+
console.log("Entity:", entityType.name);
|
|
535
|
+
console.log("Properties:", entityType.properties);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Relationship types
|
|
539
|
+
dataModel.relationshipTypes.forEach(relType => {
|
|
540
|
+
console.log("Relationship:", relType.name);
|
|
541
|
+
console.log("Origin:", relType.originEntityTypes);
|
|
542
|
+
console.log("Destination:", relType.destinationEntityTypes);
|
|
543
|
+
});
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
## Common openCypher Patterns
|
|
547
|
+
|
|
548
|
+
```cypher
|
|
549
|
+
-- Find all entities
|
|
550
|
+
MATCH (n) RETURN n
|
|
551
|
+
|
|
552
|
+
-- Find specific type
|
|
553
|
+
MATCH (p:Person) RETURN p
|
|
554
|
+
|
|
555
|
+
-- Find relationships
|
|
556
|
+
MATCH (a)-[r]->(b) RETURN a, r, b
|
|
557
|
+
|
|
558
|
+
-- Find path
|
|
559
|
+
MATCH path = (a:Person)-[:KNOWS*1..3]->(b:Person)
|
|
560
|
+
WHERE a.name = 'John'
|
|
561
|
+
RETURN path
|
|
562
|
+
|
|
563
|
+
-- Aggregate
|
|
564
|
+
MATCH (p:Person)-[:WORKS_AT]->(c:Company)
|
|
565
|
+
RETURN c.name, COUNT(p) as employeeCount
|
|
566
|
+
|
|
567
|
+
-- Spatial filter
|
|
568
|
+
MATCH (loc:Location)
|
|
569
|
+
WHERE esri.graph.ST_Intersects($geometry, loc.shape)
|
|
570
|
+
RETURN loc
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
## Common Pitfalls
|
|
574
|
+
|
|
575
|
+
1. **Authentication required**: Knowledge graph services typically require authentication
|
|
576
|
+
|
|
577
|
+
2. **Streaming for large results**: Use `executeQueryStreaming` for queries that may return many results
|
|
578
|
+
|
|
579
|
+
3. **Geometry conversion**: Convert geometries to WGS84 before using in spatial queries
|
|
580
|
+
|
|
581
|
+
4. **Case sensitivity**: openCypher property names are case-sensitive
|
|
582
|
+
|