@lde/sparql-qlever 0.3.2
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 +3 -0
- package/dist/importer.d.ts +31 -0
- package/dist/importer.d.ts.map +1 -0
- package/dist/importer.js +78 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/server.d.ts +18 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +24 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Importer as ImporterInterface, ImportFailed, ImportSuccessful, NotSupported } from '@lde/sparql-importer';
|
|
2
|
+
import { Dataset } from '@lde/dataset';
|
|
3
|
+
import { Downloader } from '@lde/distribution-downloader';
|
|
4
|
+
import { TaskRunner } from '@lde/task-runner';
|
|
5
|
+
export interface Options {
|
|
6
|
+
taskRunner: TaskRunner<unknown>;
|
|
7
|
+
indexName?: string;
|
|
8
|
+
downloader?: Downloader;
|
|
9
|
+
qleverOptions?: {
|
|
10
|
+
'ascii-prefixes-only': boolean;
|
|
11
|
+
'num-triples-per-batch': number;
|
|
12
|
+
};
|
|
13
|
+
port?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Import RDF to a QLever SPARQL server.
|
|
17
|
+
*
|
|
18
|
+
* - Use the QLever CLI because the Graph Store Protocol is not parallelized.
|
|
19
|
+
*/
|
|
20
|
+
export declare class Importer implements ImporterInterface {
|
|
21
|
+
private indexName;
|
|
22
|
+
private taskRunner;
|
|
23
|
+
private downloader;
|
|
24
|
+
private qleverOptions;
|
|
25
|
+
constructor({ taskRunner, downloader, indexName, qleverOptions }: Options);
|
|
26
|
+
import(dataset: Dataset): Promise<NotSupported | ImportSuccessful | ImportFailed>;
|
|
27
|
+
private doImport;
|
|
28
|
+
private fileFormatFromMimeType;
|
|
29
|
+
private index;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=importer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"importer.d.ts","sourceRoot":"","sources":["../src/importer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,IAAI,iBAAiB,EAC7B,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACb,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAgB,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,UAAU,EAA0B,MAAM,8BAA8B,CAAC;AAGlF,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE;QACd,qBAAqB,EAAE,OAAO,CAAC;QAC/B,uBAAuB,EAAE,MAAM,CAAC;KACjC,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,qBAAa,QAAS,YAAW,iBAAiB;IAChD,OAAO,CAAC,SAAS,CAAC;IAClB,OAAO,CAAC,UAAU,CAAsB;IACxC,OAAO,CAAC,UAAU,CAAC;IACnB,OAAO,CAAC,aAAa,CAAC;gBAEV,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,OAAO;IAU5D,MAAM,CACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,YAAY,GAAG,gBAAgB,GAAG,YAAY,CAAC;YA2B5C,QAAQ;IAYtB,OAAO,CAAC,sBAAsB;YAgBhB,KAAK;CAmBpB"}
|
package/dist/importer.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ImportFailed, ImportSuccessful, NotSupported, } from '@lde/sparql-importer';
|
|
2
|
+
import { LastModifiedDownloader } from '@lde/distribution-downloader';
|
|
3
|
+
import { basename, dirname } from 'path';
|
|
4
|
+
import { writeFile } from 'node:fs/promises';
|
|
5
|
+
/**
|
|
6
|
+
* Import RDF to a QLever SPARQL server.
|
|
7
|
+
*
|
|
8
|
+
* - Use the QLever CLI because the Graph Store Protocol is not parallelized.
|
|
9
|
+
*/
|
|
10
|
+
export class Importer {
|
|
11
|
+
indexName;
|
|
12
|
+
taskRunner;
|
|
13
|
+
downloader;
|
|
14
|
+
qleverOptions;
|
|
15
|
+
constructor({ taskRunner, downloader, indexName, qleverOptions }) {
|
|
16
|
+
this.taskRunner = taskRunner;
|
|
17
|
+
this.downloader = downloader ?? new LastModifiedDownloader();
|
|
18
|
+
this.indexName = indexName ?? 'data';
|
|
19
|
+
this.qleverOptions = qleverOptions ?? {
|
|
20
|
+
'ascii-prefixes-only': true,
|
|
21
|
+
'num-triples-per-batch': 100000,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async import(dataset) {
|
|
25
|
+
const downloadDistributions = dataset.getDownloadDistributions();
|
|
26
|
+
if (downloadDistributions.length === 0) {
|
|
27
|
+
return new NotSupported();
|
|
28
|
+
}
|
|
29
|
+
let result;
|
|
30
|
+
for (const downloadDistribution of downloadDistributions) {
|
|
31
|
+
try {
|
|
32
|
+
result = await this.doImport(downloadDistribution);
|
|
33
|
+
if (result instanceof ImportSuccessful) {
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
let errorMessage;
|
|
39
|
+
if (error instanceof AggregateError) {
|
|
40
|
+
errorMessage = error.errors.join(' / ');
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
errorMessage = error.message;
|
|
44
|
+
}
|
|
45
|
+
result = new ImportFailed(downloadDistribution, errorMessage);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
async doImport(distribution) {
|
|
51
|
+
const localFile = await this.downloader.download(distribution);
|
|
52
|
+
await this.index(localFile, this.fileFormatFromMimeType(distribution.mimeType));
|
|
53
|
+
return new ImportSuccessful(distribution);
|
|
54
|
+
}
|
|
55
|
+
fileFormatFromMimeType(mimeType) {
|
|
56
|
+
switch (mimeType) {
|
|
57
|
+
case 'application/n-triples':
|
|
58
|
+
case 'application/n-triples+gzip':
|
|
59
|
+
return 'nt';
|
|
60
|
+
case 'application/n-quads':
|
|
61
|
+
case 'application/n-quads+gzip':
|
|
62
|
+
return 'nq';
|
|
63
|
+
case 'text/turtle':
|
|
64
|
+
case 'text/turtle+gzip':
|
|
65
|
+
return 'ttl';
|
|
66
|
+
default:
|
|
67
|
+
throw new Error(`Unsupported media type: ${mimeType}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async index(file, format) {
|
|
71
|
+
const workingDir = dirname(file);
|
|
72
|
+
const settingsFile = 'index.settings.json';
|
|
73
|
+
await writeFile(`${workingDir}/${settingsFile}`, JSON.stringify(this.qleverOptions));
|
|
74
|
+
// TODO: write index to named volume instead of bind mount for better performance.
|
|
75
|
+
const indexTask = await this.taskRunner.run(`(zcat '${basename(file)}' 2>/dev/null || cat '${basename(file)}') | IndexBuilderMain -i ${this.indexName} -s ${settingsFile} -F ${format} -f -`);
|
|
76
|
+
await this.taskRunner.wait(indexTask);
|
|
77
|
+
}
|
|
78
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
ADDED
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SparqlServer } from '@lde/sparql-server';
|
|
2
|
+
import { TaskRunner } from '@lde/task-runner';
|
|
3
|
+
export declare class Server<Task> implements SparqlServer {
|
|
4
|
+
private taskRunner;
|
|
5
|
+
private readonly indexName;
|
|
6
|
+
private task?;
|
|
7
|
+
private readonly port;
|
|
8
|
+
constructor({ taskRunner, indexName, port }: Arguments<Task>);
|
|
9
|
+
start(): Promise<void>;
|
|
10
|
+
stop(): Promise<void>;
|
|
11
|
+
get queryEndpoint(): URL;
|
|
12
|
+
}
|
|
13
|
+
export interface Arguments<Task> {
|
|
14
|
+
taskRunner: TaskRunner<Task>;
|
|
15
|
+
indexName: string;
|
|
16
|
+
port?: number;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,qBAAa,MAAM,CAAC,IAAI,CAAE,YAAW,YAAY;IAC/C,OAAO,CAAC,UAAU,CAAmB;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,IAAI,CAAC,CAAO;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,EAAE,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,SAAS,CAAC,IAAI,CAAC;IAM/C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOlC,IAAW,aAAa,IAAI,GAAG,CAE9B;CACF;AAED,MAAM,WAAW,SAAS,CAAC,IAAI;IAC7B,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class Server {
|
|
2
|
+
taskRunner;
|
|
3
|
+
indexName;
|
|
4
|
+
task;
|
|
5
|
+
port;
|
|
6
|
+
constructor({ taskRunner, indexName, port }) {
|
|
7
|
+
this.taskRunner = taskRunner;
|
|
8
|
+
this.indexName = indexName;
|
|
9
|
+
this.port = port ?? 7001;
|
|
10
|
+
}
|
|
11
|
+
async start() {
|
|
12
|
+
// TODO prevent double starts.
|
|
13
|
+
this.task = await this.taskRunner.run(`ServerMain --index-basename ${this.indexName} --memory-max-size 6G --port ${this.port}`);
|
|
14
|
+
}
|
|
15
|
+
async stop() {
|
|
16
|
+
if (this.task) {
|
|
17
|
+
await this.taskRunner.stop(this.task);
|
|
18
|
+
this.task = undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
get queryEndpoint() {
|
|
22
|
+
return new URL(`http://localhost:${this.port}/sparql`);
|
|
23
|
+
}
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lde/sparql-qlever",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
"./package.json": "./package.json",
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"development": "./src/index.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"!**/*.tsbuildinfo"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"tslib": "^2.3.0",
|
|
23
|
+
"@lde/sparql-importer": "0.0.5",
|
|
24
|
+
"@lde/dataset": "0.3.1",
|
|
25
|
+
"@lde/distribution-downloader": "0.2.3",
|
|
26
|
+
"@lde/task-runner": "0.0.4",
|
|
27
|
+
"@lde/sparql-server": "0.2.1"
|
|
28
|
+
}
|
|
29
|
+
}
|