[ English | Nederlands | Deutsch | Español | Français | 日本語 ]
Kolibrie は、Rustで実装された高性能・高並行・機能豊富なSPARQLクエリエンジンです。スケーラビリティと効率性を念頭に設計されており、Rustの堅牢な並行モデルに加えて、SIMD(Single Instruction, Multiple Data)やRayonによる並列処理などの最適化を活用し、大規模なRDF(Resource Description Framework)データセットをスムーズに処理します。
包括的なAPIを備えた Kolibrie は、SPARQL、Turtle、N3形式のRDFデータの解析・保存・クエリを容易にします。高度なフィルタリング、集約、結合操作、洗練された最適化戦略により、複雑なセマンティックデータ処理が求められるアプリケーションに適しています。さらに、Volcano Optimizerの統合とReasoner(知識グラフ推論)機能によって、コストに基づく効率的なクエリプランニングとルールベース推論を活用した高度なデータ分析が可能になります。
Kolibrie は、KU Leuvenの Stream Intelligence Lab にて、Pieter Bonte教授の指導のもと開発されています。Stream Intelligence Labは Stream Reasoning(ストリーム推論) に焦点を当てており、継続的なデータストリームからタイムリーで実用的な知識を導出するために、AIにおける論理的手法とデータ駆動型の機械学習アプローチを統合する新興研究分野です。私たちの研究は、IoTやエッジ処理領域の応用に重点を置き、自動運転車、ロボティクス、ウェブ分析などの動的な環境におけるリアルタイム意思決定を可能にします。
研究や進行中プロジェクトの詳細は、Stream Intelligence Labのウェブサイトをご覧ください。
- Efficient RDF Parsing: RDF/XML、Turtle、N3形式の解析をサポートし、堅牢なエラーハンドリングとプレフィックス管理を提供します。
- Concurrent Processing: RayonとCrossbeamを活用した並列データ処理で、マルチコア環境における最適なパフォーマンスを実現します。
- SIMD Optimizations: フィルタリングや集約を高速化するためのSIMD最適化を実装しています。
- Flexible Querying: SELECT、INSERT、FILTER、GROUP BY、VALUES などを含む複雑なSPARQLクエリに対応します。
- Volcano Optimizer: Volcanoモデルに基づくコストベース最適化で、最も効率的な実行プランを選択します。
- Reasoner: ABox(インスタンス)およびTBox(スキーマ)のアサーションを含む知識グラフの構築とクエリに対応し、動的ルール推論とバックワードチェイニングを提供します。
- Streaming and Sliding Windows: タイムスタンプ付きトリプルおよびスライディングウィンドウを扱う時間的分析をサポートします。
- Extensible Dictionary Encoding: カスタマイズ可能な辞書によりRDF用語を効率的にエンコード/デコードします。
- Comprehensive API: データ操作、クエリ、結果処理のための豊富なメソッド群を提供します。
Warning
CUDAの利用は実験的で、現在開発中です。
Rust(1.60以上)をインストールしてください。
リポジトリをクローン:
git clone https://github.com/StreamIntelligenceLab/Kolibrie.git
cd Kolibrieビルド:
cargo build --releaseプロジェクトで使用:
use kolibrie::SparqlDatabase;Kolibrie は、用途に応じた複数のDockerプロファイルを提供します。Docker設定はRust、CUDA(GPUビルド向け)、PythonのMLフレームワークを含む依存関係を自動的に処理します。
- Docker がインストールされていること
- Docker Compose がインストールされていること
- GPUサポート用:NVIDIA Docker runtime がインストールされていること
- CPUのみビルド(多くのユーザーに推奨):
docker compose --profile cpu up --build- GPU対応ビルド(NVIDIA GPU + nvidia-dockerが必要):
docker compose --profile gpu up --build- 開発ビルド(GPUの有無を自動検出):
docker compose --profile dev up --builduse kolibrie::SparqlDatabase;
fn main() {
let mut db = SparqlDatabase::new();
// Your code here
}db.parse_rdf_from_file("data.rdf");let rdf_data = r#"
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:foaf="http://xmlns.com/foaf/0. 1/">
<rdf:Description rdf:about="http://example.org/alice">
<foaf:name>Alice</foaf:name>
<foaf:age>30</foaf:age>
</rdf:Description>
</rdf:RDF>
"#;
db.parse_rdf(rdf_data);let turtle_data = r#"
@prefix ex: <http://example.org/> .
ex:Alice ex:knows ex:Bob .
ex:Bob ex:knows ex:Charlie .
"#;
db.parse_turtle(turtle_data);let n3_data = r#"
@prefix ex: <http://example.org/> .
ex:Alice ex:knows ex:Bob .
ex:Bob ex:knows ex:Charlie .
"#;
db.parse_n3(n3_data);let ntriples_data = r#"
<http://example.org/john> <http://example.org/hasFriend> <http://example.org/jane> .
<http://example.org/jane> <http://example.org/name> "Jane Doe" .
<http://example.org/john> <http://example.org/age> "30"^^<http://www.w3.org/2001/XMLSchema#integer> .
"#;
db.parse_ntriples_and_add(ntriples_data);db.add_triple_parts(
"http://example.org/alice",
"http://xmlns.com/foaf/0.1/name",
"Alice"
);
db.add_triple_parts(
"http://example.org/alice",
"http://xmlns.com/foaf/0.1/age",
"30"
);use kolibrie::execute_query::execute_query;
let sparql_query = r#"
PREFIX ex: <http://example.org/>
SELECT ?s ?o
WHERE {
?s ex:knows ?o .
}
"#;
let results = execute_query(sparql_query, &mut db);
for row in results {
println!("Subject: {}, Object: {}", row[0], row[1]);
}let sparql = r#"
PREFIX ex: <http://example.org/vocab#>
SELECT ?name ?attendees
WHERE {
?event ex:name ?name .
?event ex:attendees ?attendees .
FILTER (?attendees > 50)
}
"#;
let results = execute_query(sparql, &mut db);
for row in results {
println! ("Event: {}, Attendees: {}", row[0], row[1]);
}let sparql = r#"
PREFIX ex: <http://example.org/vocab#>
SELECT ?name ?type ?attendees
WHERE {
?event ex:name ?name .
?event ex:type ?type .
?event ex:attendees ?attendees .
FILTER (?type = "Technical" || ?type = "Academic")
}
"#;
let results = execute_query(sparql, &mut db);
for row in results {
if let [name, type_, attendees] = &row[.. ] {
println!("Name: {}, Type: {}, Attendees: {}", name, type_, attendees);
}
}let sparql = r#"
PREFIX ex: <http://example.org/vocab#>
SELECT ?name ?type
WHERE {
?event ex:name ?name .
?event ex:type ?type .
FILTER (?type = "Technical" || ?type = "Academic")
}
LIMIT 2
"#;
let results = execute_query(sparql, &mut db);
for row in results {
println!("Name: {}, Type: {}", row[0], row[1]);
}let sparql = r#"
PREFIX ds: <https://data.cityofchicago.org/resource/xzkq-xp2w/>
SELECT AVG(?salary) AS ?average_salary
WHERE {
?employee ds:annual_salary ?salary
}
GROUPBY ?average_salary
"#;
let results = execute_query(sparql, &mut db);
for row in results {
if let [avg_salary] = &row[.. ] {
println!("Average Salary: {}", avg_salary);
}
}Supported Aggregations:
AVG(?var)- 平均COUNT(?var)- 件数SUM(?var)- 合計MIN(?var)- 最小MAX(?var)- 最大
let sparql = r#"
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?name
WHERE {
?person foaf:givenName ?first .
?person foaf:surname ?last
BIND(CONCAT(?first, " ", ?last) AS ?name)
}
"#;
let results = execute_query(sparql, &mut db);
for row in results {
println!("Full Name: {}", row[0]);
}let sparql = r#"
PREFIX ex: <http://example.org/>
SELECT ?friendName
WHERE {
?person ex:name "Alice" .
?person ex:knows ?friend
{
SELECT ?friend ?friendName
WHERE {
?friend ex:name ?friendName .
}
}
}"#;
let results = execute_query(sparql, &mut db);
for row in results {
println!("Alice's Friend: {}", row[0]);
}// Get all objects for a specific predicate
let results = db.query()
.with_predicate("http://xmlns.com/foaf/0.1/name")
.get_objects();
for object in results {
println!("Name: {}", object);
}let results = db.query()
.with_predicate("http://xmlns.com/foaf/0.1/age")
.filter(|triple| {
db.dictionary.decode(triple.object)
.and_then(|age| age.parse::<i32>().ok())
.map(|age| age > 25)
.unwrap_or(false)
})
.get_decoded_triples();
for (subject, predicate, object) in results {
println!("{} is {} years old", subject, object);
}let other_db = SparqlDatabase::new();
// ... populate other_db ...
let results = db.query()
.join(&other_db)
.join_on_subject()
.get_triples();let results = db.query()
.with_predicate("http://xmlns.com/foaf/0.1/name")
.order_by(|triple| {
db.dictionary.decode(triple.object).unwrap().to_string()
})
.distinct()
.limit(10)
.offset(5)
.get_decoded_triples();
for (subject, predicate, object) in results {
println!("{} - {} - {}", subject, predicate, object);
}use kolibrie::execute_query::*;
use kolibrie::sparql_database::*;
fn main() {
let mut db = SparqlDatabase::new();
// Parse N-Triples data
let ntriples_data = r#"
<http://example.org/john> <http://example.org/hasFriend> <http://example.org/jane> .
<http://example.org/jane> <http://example.org/name> "Jane Doe" .
<http://example.org/john> <http://example.org/name> "John Smith" .
<http://example.org/jane> <http://example.org/age> "25"^^<http://www.w3.org/2001/XMLSchema#integer> .
<http://example.org/john> <http://example.org/age> "30"^^<http://www. w3.org/2001/XMLSchema#integer> .
"#;
db.parse_ntriples_and_add(ntriples_data);
// Build statistics for the optimizer
db.get_or_build_stats();
// Define the SPARQL query
let sparql_query = r#"
PREFIX ex: <http://example.org/>
SELECT ?person ?friend ?friendName
WHERE {
?person ex:hasFriend ?friend .
?friend ex:name ?friendName .
}
"#;
// Execute the query with optimized plan
let results = execute_query(sparql_query, &mut db);
for row in results {
println!("Person: {}, Friend: {}, Friend's Name: {}", row[0], row[1], row[2]);
}
}use datalog::knowledge_graph::Reasoner;
use shared::terms::Term;
use shared::rule::Rule;
fn main() {
let mut kg = Reasoner::new();
// Add ABox triples (instance-level data)
kg.add_abox_triple("Alice", "parentOf", "Bob");
kg.add_abox_triple("Bob", "parentOf", "Charlie");
// Rule: parentOf(X, Y) ∧ parentOf(Y, Z) → ancestorOf(X, Z)
let ancestor_rule = Rule {
premise: vec![
(
Term::Variable("X".to_string()),
Term::Constant(kg.dictionary.encode("parentOf")),
Term::Variable("Y".to_string()),
),
(
Term::Variable("Y". to_string()),
Term::Constant(kg.dictionary.encode("parentOf")),
Term::Variable("Z".to_string()),
),
],
conclusion: vec![
(
Term::Variable("X".to_string()),
Term::Constant(kg.dictionary.encode("ancestorOf")),
Term::Variable("Z".to_string()),
)
],
filters: vec![],
};
kg.add_rule(ancestor_rule);
// Infer new facts using forward chaining
let inferred_facts = kg.infer_new_facts();
println!("Inferred {} new facts", inferred_facts.len());
// Query the Knowledge Graph for ancestorOf relationships
let results = kg.query_abox(
Some("Alice"),
Some("ancestorOf"),
None,
);
for triple in results {
println!(
"{} is ancestor of {}",
kg.dictionary.decode(triple.subject).unwrap(),
kg. dictionary.decode(triple.object). unwrap()
);
}
}Kolibrie は以下の最適化により高性能を実現しています:
- Parallel Parsing and Processing: RayonとCrossbeamによるマルチスレッド解析/実行。
- SIMD Instructions: フィルタリングや集約の高速化。
- Volcano Optimizer: コストベース最適化で効率的な物理プランを生成。
- Knowledge Graph Inference: ルールベース推論/バックワードチェイニングを効率的に統合。
- Efficient Data Structures:
BTreeSetやHashMapなどを用途に応じて活用。 - Memory Optimization: 辞書エンコーディングでメモリ使用量を縮小。
ベンチマークでは、Kolibrieが既存のRDFエンジンに対して優位な性能を示すことを確認しています。
- Dataset: WatDiv 10M triples benchmark
- Oxigraph Configuration: RocksDB backend
- Deep Taxonomy Reasoning: 階層深度は最大10Kレベルまで評価
Figure 1: WatDiv 10Mにおける各SPARQLエンジンのクエリ実行時間
Key Findings:
- Kolibrieは各クエリ形状(L1-L5, S1-S7, F1-F3, C1-C3)で一貫して高い性能を示します。
- 平均クエリ実行時間は サブミリ秒〜低ミリ秒 の範囲。
- BlazegraphとQLeverは一部形状で競争力のある性能を示します。
- Oxigraph(RocksDB)は全体的に安定した性能を提供します。
Figure 2: 階層深度(10, 100, 1K, 10K)に対する推論性能
Key Findings:
- Kolibrieは階層深度に対して 対数的なスケーリング を示します。
- 10Kレベルでもサブ秒の応答を維持。
- Apache JenaやEYE reasonerに対して優れた性能。
- 複雑なタクソノミ構造を効率的に処理可能。
Issue Trackerを使用して、バグ報告や新機能/改善のリクエストを提出してください。新しい問題を提出する前に、類似のオープンなIssueがないことを確認してください。
コードを手動でテストし、バグや改善提案をIssue Trackerに報告してくださる方は大歓迎です!
パッチや修正はプルリクエスト(PR)の形式で受け付けています。プルリクエストが対処するIssueがIssue Trackerにオープンしていることを確認してください。
提出されたプルリクエストは、Mozilla Public License Version 2.0 の下で公開することに同意したとみなされます。
Kolibrieについて議論し、質問し、経験を共有するために、Discordコミュニティに参加してください。
KolibrieはMPL-2.0ライセンスの下でライセンスされています。

