arcgis-knowledge-graphs について
arcgis-knowledge-graphsは、JavaScriptでArcGISナレッジグラフサービスやリンクチャートを扱うためのスキルです。ArcGIS APIを使う開発者向けに、グラフの検索、編集、クエリ、エンティティ関係の可視化を解説します。
主な機能
- 01グラフのメタデータとデータモデルを取得
- 02openCypherクエリの実行とストリーミング
- 03グラフのエンティティと関係を検索
- 04グラフレコードの追加・更新・削除
- 05リンクチャートの可視化と展開
活用シーン
- 01openCypherでグラフデータをクエリ
- 02大規模なクエリ結果をストリーミング
- 03グラフのエンティティや関係を編集
- 04リンクチャートで関連レコードを探索
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ saschabrunnerch/ arcgis-maps-sdk-js-ai-context --skill arcgis-knowledge-graphsインストール後、Claude Code で/arcgis-knowledge-graphsを入力して読み込まれたか確認します。
詳細
ArcGIS ナレッジグラフ
ナレッジグラフ、グラフクエリ(openCypher)、リンクチャートの可視化、エンティティとリレーションシップの管理にこのスキルを使用します。
インポートパターン
ESM(npm)
// Knowledge graph service
import * as knowledgeGraphService from "@arcgis/core/rest/knowledgeGraphService.js";
// Layers
import KnowledgeGraphLayer from "@arcgis/core/layers/KnowledgeGraphLayer.js";
import LinkChartLayer from "@arcgis/core/layers/LinkChartLayer.js";
// Views and charts
import WebLinkChart from "@arcgis/core/WebLinkChart.js";
import LinkChartView from "@arcgis/core/views/LinkChartView.js";
// Layout settings
import OrganicLayoutSettings from "@arcgis/core/linkChart/OrganicLayoutSettings.js";
import ChronologicalLayoutSettings from "@arcgis/core/linkChart/ChronologicalLayoutSettings.js";
import LinkChartLayoutSwitcher from "@arcgis/core/linkChart/LinkChartLayoutSwitcher.js";
CDN(動的インポート)
const knowledgeGraphService = await $arcgis.import(
"@arcgis/core/rest/knowledgeGraphService.js",
);
const KnowledgeGraphLayer = await $arcgis.import(
"@arcgis/core/layers/KnowledgeGraphLayer.js",
);
const WebLinkChart = await $arcgis.import("@arcgis/core/WebLinkChart.js");
const LinkChartView = await $arcgis.import(
"@arcgis/core/views/LinkChartView.js",
);
ナレッジグラフサービス
ナレッジグラフを取得する
const url =
"https://your-server/server/rest/services/Hosted/YourKG/KnowledgeGraphServer";
const knowledgeGraph = await knowledgeGraphService.fetchKnowledgeGraph(url);
console.log("Graph name:", knowledgeGraph.name);
console.log("Entity types:", knowledgeGraph.dataModel.entityTypes);
console.log("Relationship types:", knowledgeGraph.dataModel.relationshipTypes);
サービス関数
| 関数 | 説明 |
|---|---|
fetchKnowledgeGraph(url) | ナレッジグラフのメタデータとデータモデルを取得します |
executeQuery(kg, params) | openCypher クエリを実行し、すべての結果を返します |
executeQueryStreaming(kg, params) | 大規模なクエリ結果をストリーミングします |
executeSearch(kg, params) | エンティティ全体を対象に全文検索します |
executeApplyEdits(kg, params) | エンティティとリレーションシップを追加、更新、削除します |
KnowledgeGraphLayer
マップに追加する
const kgLayer = new KnowledgeGraphLayer({
url: "https://your-server/server/rest/services/Hosted/YourKG/KnowledgeGraphServer",
});
await kgLayer.load();
map.add(kgLayer);
サブレイヤーを構成する
const kgLayer = new KnowledgeGraphLayer({
url: "...",
inclusionModeDefinition: {
generateAllSublayers: false,
namedTypeDefinitions: new Map([
["Person", { useAllData: true }],
["Location", { useAllData: true }],
]),
},
});
openCypher でクエリを実行する
基本的なクエリ
const result = await knowledgeGraphService.executeQuery(knowledgeGraph, {
openCypherQuery: "MATCH (n:Person) RETURN n LIMIT 10",
});
console.log("Results:", result.resultRows);
ストリーミングクエリ(大規模な結果)
const queryResults = await knowledgeGraphService.executeQueryStreaming(
knowledgeGraph,
{
openCypherQuery: "MATCH (n:Person)-[r]->(m) RETURN n, r, m",
},
);
const reader = queryResults.resultRowsStream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
value.forEach((row) => {
console.log("Row:", row);
});
}
バインドパラメーターを使用した空間クエリ
import Polygon from "@arcgis/core/geometry/Polygon.js";
const searchArea = new Polygon({
rings: [
[
[-76, 45],
[-70, 45],
[-70, 40],
[-76, 40],
[-76, 45],
],
],
});
const queryResults = await knowledgeGraphService.executeQueryStreaming(
knowledgeGraph,
{
openCypherQuery: `
MATCH path=(a:User)-[]->(b:Observation)
WHERE esri.graph.ST_Intersects($geometry, b.shape)
RETURN path
`,
bindParameters: {
geometry: searchArea,
},
},
);
フィルターを使用したクエリ
// Filter by property
const result = await knowledgeGraphService.executeQuery(knowledgeGraph, {
openCypherQuery: `
MATCH (p:Person)
WHERE p.age > 30 AND p.name CONTAINS 'John'
RETURN p
`,
});
// Query relationships
const result = await knowledgeGraphService.executeQuery(knowledgeGraph, {
openCypherQuery: `
MATCH (p:Person)-[r:WORKS_AT]->(c:Company)
WHERE c.name = 'Esri'
RETURN p.name, r.startDate, c.name
`,
});
一般的な openCypher パターン
-- Find all entities of a type
MATCH (p:Person) RETURN p
-- Find relationships
MATCH (a)-[r]->(b) RETURN a, r, b
-- Find path with depth
MATCH path = (a:Person)-[:KNOWS*1..3]->(b:Person)
WHERE a.name = 'John'
RETURN path
-- Aggregate
MATCH (p:Person)-[:WORKS_AT]->(c:Company)
RETURN c.name, COUNT(p) as employeeCount
-- Spatial filter
MATCH (loc:Location)
WHERE esri.graph.ST_Intersects($geometry, loc.shape)
RETURN loc
ナレッジグラフを検索する
const searchResults = await knowledgeGraphService.executeSearch(
knowledgeGraph,
{
searchQuery: "John Smith",
typeCategoryFilter: "entity", // "entity", "relationship", "both"
typeNames: ["Person", "Employee"],
returnSearchContext: true,
},
);
searchResults.results.forEach((result) => {
console.log("Found:", result.typeName, result.id);
console.log("Context:", result.searchContext);
});
編集を適用する
// Add entity
await knowledgeGraphService.executeApplyEdits(knowledgeGraph, {
entityAdds: [
{
typeName: "Person",
properties: { name: "Jane Doe", age: 28 },
},
],
});
// Update entity
await knowledgeGraphService.executeApplyEdits(knowledgeGraph, {
entityUpdates: [
{
typeName: "Person",
properties: { globalId: "{existing-global-id}", age: 29 },
},
],
});
// Delete entity
await knowledgeGraphService.executeApplyEdits(knowledgeGraph, {
entityDeletes: [
{
typeName: "Person",
ids: ["{global-id-to-delete}"],
},
],
});
// Add relationship
await knowledgeGraphService.executeApplyEdits(knowledgeGraph, {
relationshipAdds: [
{
typeName: "WORKS_AT",
properties: {
originGlobalId: "{person-global-id}",
destinationGlobalId: "{company-global-id}",
startDate: new Date(),
},
},
],
});
データモデル
const dataModel = knowledgeGraph.dataModel;
dataModel.entityTypes.forEach((entityType) => {
console.log("Entity:", entityType.name);
console.log("Properties:", entityType.properties);
});
dataModel.relationshipTypes.forEach((relType) => {
console.log("Relationship:", relType.name);
console.log("Origin:", relType.originEntityTypes);
console.log("Destination:", relType.destinationEntityTypes);
});
リンクチャートの可視化
リンクチャートを作成する(コア API)
const linkChartLayer = new LinkChartLayer({
url: "https://your-server/.../KnowledgeGraphServer",
});
const linkChart = new WebLinkChart({
layers: [linkChartLayer],
});
const linkChartView = new LinkChartView({
container: "linkChartDiv",
map: linkChart,
highlightOptions: {
color: [0, 255, 255, 1],
haloColor: [0, 255, 255, 0.5],
haloOpacity: 0.8,
},
});
リンクチャートコンポーネント
<arcgis-link-chart>
<arcgis-legend slot="top-right"></arcgis-legend>
<arcgis-zoom slot="bottom-right"></arcgis-zoom>
</arcgis-link-chart>
<script type="module">
const linkChartComponent = document.querySelector("arcgis-link-chart");
await linkChartComponent.componentOnReady();
const lcView = linkChartComponent.view;
const linkChart = lcView.map;
await linkChart.addRecords([
{ id: "entity1", typeName: "Person" },
{ id: "entity2", typeName: "Company" },
]);
</script>
レコードの追加と削除
// Add records
await linkChart.addRecords([
{ id: "person-1", typeName: "Person" },
{ id: "company-1", typeName: "Company" },
{ id: "rel-1", typeName: "WORKS_AT" },
]);
// Remove records
await linkChart.removeRecords([{ id: "person-1", typeName: "Person" }]);
エンティティを展開する
await linkChart.expand({
ids: ["entity-id"],
typeName: "Person",
relationshipTypes: ["KNOWS", "WORKS_AT"],
direction: "both", // "outgoing", "incoming", "both"
});
エンティティに移動する
linkChartView.goTo([{ id: "person-1", typeName: "Person" }]);
リンクチャートのイベント
linkChartView.on("click", async (event) => {
const response = await linkChartView.hitTest(event);
if (response.results.length > 0) {
const graphic = response.results[0].graphic;
console.log("Clicked:", graphic.attributes);
}
});
クエリ結果からリンクチャートを更新する
async function updateLinkChart(queryResults, linkChart) {
const reader = queryResults.resultRowsStream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const records = [];
for (const row of value) {
for (const record of row[0].path) {
records.push({
id: record.id,
typeName: record.typeName,
});
}
}
await linkChart.addRecords(records);
}
}
レイアウト設定
オーガニックレイアウト
const organicLayout = new OrganicLayoutSettings();
linkChart.layoutSettings = organicLayout;
時系列レイアウト
const chronoLayout = new ChronologicalLayoutSettings();
linkChart.layoutSettings = chronoLayout;
レイアウト切り替えウィジェット
const layoutSwitcher = new LinkChartLayoutSwitcher({
view: linkChartView,
});
linkChartView.ui.add(layoutSwitcher, "top-right");
レイアウト切り替えコンポーネント
<arcgis-link-chart>
<arcgis-link-chart-layout-switcher
slot="top-right"
></arcgis-link-chart-layout-switcher>
</arcgis-link-chart>
WebLinkChart のプロパティ
const webLinkChart = new WebLinkChart({
portalItem: { id: "LINKCHART_ID" },
layoutSettings: organicLayout,
});
// Save to portal
await webLinkChart.saveAs({
title: "My Link Chart",
snippet: "Visualization of entity relationships",
});
よくある落とし穴
-
認証が必要です:ナレッジグラフサービスでは通常、認証が必要です。認証情報または OAuth を設定してください。
-
大規模な結果にはストリーミングを使用します:多数の結果が返される可能性があるクエリには
executeQueryStreamingを使用してください。executeQueryはすべてをメモリに読み込みます。 -
ジオメトリの変換:
esri.graph.ST_Intersectsを使用した空間クエリで使用する前に、ジオメトリを WGS84 に変換してください。 -
大文字と小文字の区別:openCypher のプロパティ名では大文字と小文字が区別されます。
p.Nameとp.nameは異なります。 -
クエリの前に読み込む:サブレイヤーやメタデータにアクセスする前に、
await kgLayer.load()が実行されていることを確認してください。 -
リンクチャートのレコード:リンクを表示するには、エンティティとリレーションシップの両方をレコードとして追加する必要があります。
リファレンスサンプル
knowledgegraph-query— openCypher を使用したナレッジグラフのクエリknowledgegraph-knowledgegraphlayer— KnowledgeGraphLayer の使用knowledgegraph-search— 全文検索knowledgegraph-applyedits— グラフエンティティの編集knowledgegraph-datamodelediting— データモデルの編集linkchart— リンクチャートの可視化
関連スキル
arcgis-layers— レイヤーの構成と管理arcgis-interaction— ヒットテストとイベント処理arcgis-editing— フィーチャ編集のパターン
コメント
Markdown 対応