Chuyển tới nội dung chính

FusekiService - SPARQL Triplestore Client

TypeScript client for Apache Jena Fuseki RDF triplestore providing SPARQL query execution, LOD linkset enrichment, and semantic data integration.

Overview

graph TB
subgraph FusekiService
CLIENT[SPARQL Client]
QUERY[Query Builder]
PARSER[Result Parser]
end

subgraph Fuseki["Apache Jena Fuseki"]
DATASET[(LOD Dataset)]
SPARQL["/sparql endpoint"]
UPDATE["/update endpoint"]
end

subgraph LOD["Linked Open Data"]
GEONAMES[GeoNames]
DBPEDIA[DBpedia]
SCHEMA[Schema.org]
SOSA[SOSA/SSN]
end

CLIENT --> QUERY
QUERY --> SPARQL
SPARQL --> DATASET
PARSER --> CLIENT

GEONAMES -.-> DATASET
DBPEDIA -.-> DATASET
SCHEMA -.-> DATASET
SOSA -.-> DATASET

Features

FeatureDescription
SPARQL 1.1SELECT, CONSTRUCT, ASK, DESCRIBE queries
GeoNames IntegrationCity/district geographic metadata
DBpedia LinksEntity definitions and multilingual labels
Federated QueriesCross-endpoint SPARQL queries
RDF SerializationTurtle, JSON-LD, N-Triples
PaginationLIMIT/OFFSET for large result sets

Class Definition

import ParsingClient from 'sparql-http-client/ParsingClient';

export class FusekiService {
private client: ParsingClient;
private endpointUrl: string;

constructor();

// Traffic Queries
queryTrafficPatterns(): Promise<TrafficPattern[]>;
queryRoadSegments(): Promise<RoadSegment[]>;
queryHistoricalData(roadSegment: string, days?: number): Promise<HistoricalData[]>;

// LOD Enrichment
getEnrichedCameraEntity(id: string): Promise<EnrichedEntity>;
queryGeoNamesLocation(lat: number, lon: number): Promise<GeoNamesData>;
queryDBpediaAbstract(entityType: string): Promise<string>;

// Generic SPARQL
executeSelect(query: string): Promise<any[]>;
executeConstruct(query: string): Promise<any>;
executeAsk(query: string): Promise<boolean>;
}

Configuration

// Environment Variables
const config = {
FUSEKI_URL: 'http://localhost:3030',
FUSEKI_DATASET: 'lod-dataset',
FUSEKI_USER: 'admin',
FUSEKI_PASSWORD: 'test_admin'
};

// Endpoint URL construction
const endpointUrl = `${FUSEKI_URL}/${FUSEKI_DATASET}/sparql`;
// Example: http://localhost:3030/lod-dataset/sparql

Usage Examples

Traffic Pattern Queries

import { FusekiService } from './services/fusekiService';

const fuseki = new FusekiService();

// Query current traffic patterns
const patterns = await fuseki.queryTrafficPatterns();
patterns.forEach(pattern => {
console.log(`${pattern.roadSegment}: ${pattern.congestionLevel}`);
console.log(`Speed: ${pattern.averageSpeed} km/h`);
console.log(`Vehicles: ${pattern.vehicleCount}`);
});

Historical Data Analysis

// Get 7-day historical data for a road segment
const history = await fuseki.queryHistoricalData(
'urn:ngsi-ld:RoadSegment:nguyen-hue',
7
);

history.forEach(record => {
console.log(`${record.date}: ${record.averageSpeed} km/h`);
});

Road Segment Discovery

// Get all road segments
const segments = await fuseki.queryRoadSegments();
segments.forEach(segment => {
console.log(`${segment.name}: ${segment.id}`);
console.log(`Start: ${segment.startPoint.latitude}, ${segment.startPoint.longitude}`);
console.log(`End: ${segment.endPoint.latitude}, ${segment.endPoint.longitude}`);
});

SPARQL Query Examples

Traffic Patterns Query

PREFIX traffic: <http://traffic.hcmc.vn/ontology#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT ?pattern ?roadSegment ?avgSpeed ?vehicleCount ?congestion ?lat ?lon ?timestamp
WHERE {
?pattern a traffic:TrafficPattern ;
traffic:roadSegment ?roadSegment ;
traffic:averageSpeed ?avgSpeed ;
traffic:vehicleCount ?vehicleCount ;
traffic:congestionLevel ?congestion ;
geo:lat ?lat ;
geo:long ?lon ;
traffic:timestamp ?timestamp .
}
ORDER BY DESC(?timestamp)
LIMIT 100

Road Segments Query

PREFIX traffic: <http://traffic.hcmc.vn/ontology#>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>

SELECT ?segment ?name ?startLat ?startLon ?endLat ?endLon
WHERE {
?segment a traffic:RoadSegment ;
traffic:name ?name ;
traffic:startPoint ?start ;
traffic:endPoint ?end .
?start geo:lat ?startLat ;
geo:long ?startLon .
?end geo:lat ?endLat ;
geo:long ?endLon .
}

Historical Data Query

PREFIX traffic: <http://traffic.hcmc.vn/ontology#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT ?date ?avgSpeed ?vehicleCount
WHERE {
?observation a traffic:TrafficObservation ;
traffic:roadSegment "urn:ngsi-ld:RoadSegment:001" ;
traffic:date ?date ;
traffic:averageSpeed ?avgSpeed ;
traffic:vehicleCount ?vehicleCount .
FILTER(?date >= "2025-11-20T00:00:00Z"^^xsd:dateTime)
}
ORDER BY ?date

GeoNames Federation

PREFIX gn: <http://www.geonames.org/ontology#>

SELECT ?name ?population ?country
WHERE {
SERVICE <http://factforge.net/sparql> {
?city gn:name ?name ;
gn:population ?population ;
gn:countryCode "VN" .
FILTER(?population > 100000)
}
}

DBpedia Enrichment

PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?abstract ?label
WHERE {
SERVICE <http://dbpedia.org/sparql> {
<http://dbpedia.org/resource/Ho_Chi_Minh_City>
dbo:abstract ?abstract ;
rdfs:label ?label .
FILTER(lang(?abstract) = "en")
FILTER(lang(?label) = "en")
}
}

LOD Enrichment Pipeline

flowchart LR
A[NGSI-LD Entity] --> B[Extract Location]
B --> C[Query GeoNames]
C --> D[Get Admin Regions]
D --> E[Query DBpedia]
E --> F[Get Abstracts]
F --> G[Enriched Entity]

style A fill:#e1f5fe
style G fill:#c8e6c9

Enriched Entity Example

{
"id": "urn:ngsi-ld:Camera:001",
"type": "Camera",
"name": "Camera Nguyen Hue",
"location": {
"latitude": 10.7731,
"longitude": 106.7030
},
"enrichment": {
"geonames": {
"adminLevel1": "Ho Chi Minh City",
"adminLevel2": "District 1",
"featureClass": "P",
"population": 8993082
},
"dbpedia": {
"abstract": "Ho Chi Minh City is the largest city in Vietnam...",
"wikiLink": "https://en.wikipedia.org/wiki/Ho_Chi_Minh_City"
}
}
}

Ontology Namespaces

PrefixNamespaceDescription
traffichttp://traffic.hcmc.vn/ontology#UIP Traffic Ontology
geohttp://www.w3.org/2003/01/geo/wgs84_pos#WGS84 Geo Positioning
sosahttp://www.w3.org/ns/sosa/Sensor Observation
ssnhttp://www.w3.org/ns/ssn/Semantic Sensor Network
schemahttp://schema.org/Schema.org Vocabulary
gnhttp://www.geonames.org/ontology#GeoNames Ontology
dbohttp://dbpedia.org/ontology/DBpedia Ontology

Error Handling

async queryTrafficPatterns(): Promise<TrafficPattern[]> {
try {
const stream = await this.client.query.select(query);
const results: TrafficPattern[] = [];

for await (const row of stream) {
results.push(this.mapTrafficPattern(row));
}

return results;
} catch (error) {
logger.error('SPARQL query failed:', error);
throw new Error('Failed to query traffic patterns from Fuseki');
}
}

Performance Considerations

AspectRecommendation
Query ComplexityUse LIMIT for large result sets
Federated QueriesCache external endpoint results
IndexesConfigure Fuseki TDB2 indexes
TimeoutsSet query timeout in Fuseki config

Fuseki Configuration

# fuseki-config.ttl
:service a fuseki:Service ;
fuseki:name "lod-dataset" ;
fuseki:endpoint [
fuseki:operation fuseki:query ;
fuseki:name "sparql" ;
ja:context [
ja:cxtName "arq:queryTimeout" ;
ja:cxtValue "30000" # 30s timeout
]
] .

References