@lde/search-pipeline 0.15.0 → 0.15.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/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/search-indexer-pipeline.d.ts +19 -0
- package/dist/search-indexer-pipeline.d.ts.map +1 -1
- package/dist/search-indexer-pipeline.js +26 -2
- package/dist/search-stages.d.ts +48 -1
- package/dist/search-stages.d.ts.map +1 -1
- package/dist/search-stages.js +44 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { searchIndexerPipeline } from './search-indexer-pipeline.js';
|
|
2
2
|
export type { SearchIndexerPipelineOptions } from './search-indexer-pipeline.js';
|
|
3
|
-
export { searchStages, selectByClass } from './search-stages.js';
|
|
3
|
+
export { registrySource, searchStages, selectByClass, } from './search-stages.js';
|
|
4
4
|
export type { SearchStagesOptions, SearchStageType } from './search-stages.js';
|
|
5
5
|
export { extractionQuery, extractionQueryString } from './extraction.js';
|
|
6
6
|
export type { ExtractionOptions } from './extraction.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,YAAY,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,YAAY,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACzE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { searchIndexerPipeline } from './search-indexer-pipeline.js';
|
|
2
|
-
export { searchStages, selectByClass } from './search-stages.js';
|
|
2
|
+
export { registrySource, searchStages, selectByClass, } from './search-stages.js';
|
|
3
3
|
export { extractionQuery, extractionQueryString } from './extraction.js';
|
|
4
4
|
export { searchIndexWriter } from './search-index-writer.js';
|
|
@@ -35,6 +35,25 @@ export interface SearchIndexerPipelineOptions {
|
|
|
35
35
|
* it.
|
|
36
36
|
*/
|
|
37
37
|
writerFor: (searchType: RootType, schema: SearchSchema) => Writer<SearchDocument>;
|
|
38
|
+
/**
|
|
39
|
+
* Root types whose triples come from the **dataset registry** rather than
|
|
40
|
+
* from each dataset’s own distribution – typically the dataset description
|
|
41
|
+
* itself and what hangs off it, which live in the register because
|
|
42
|
+
* registering a dataset is submitting a description
|
|
43
|
+
* ({@link registrySource}).
|
|
44
|
+
*
|
|
45
|
+
* Routing is deployment topology, so it is configured here and not declared
|
|
46
|
+
* on the {@link SearchType}: a type is defined by its `class`, not by where
|
|
47
|
+
* its triples come from. Name the types by their `name`; an unknown name
|
|
48
|
+
* throws here, at wiring time, rather than yielding an empty collection at
|
|
49
|
+
* run time.
|
|
50
|
+
*/
|
|
51
|
+
registryTypes?: {
|
|
52
|
+
/** The registry’s SPARQL endpoint – where these types read. */
|
|
53
|
+
endpoint: URL;
|
|
54
|
+
/** {@link SearchType.name}s of the root types to source from it. */
|
|
55
|
+
names: readonly string[];
|
|
56
|
+
};
|
|
38
57
|
/**
|
|
39
58
|
* Optional per-dataset processing memory: skip a dataset whose source
|
|
40
59
|
* fingerprint and {@link pipelineVersion} both match the stored record.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-indexer-pipeline.d.ts","sourceRoot":"","sources":["../src/search-indexer-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAEL,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"search-indexer-pipeline.d.ts","sourceRoot":"","sources":["../src/search-indexer-pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAEL,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,MAAM,EACZ,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO1E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,iDAAiD;AACjD,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC;IACtC;;;;;;;;OAQG;IACH,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IAC5C;;;;;;;OAOG;IACH,SAAS,EAAE,CACT,UAAU,EAAE,QAAQ,EACpB,MAAM,EAAE,YAAY,KACjB,MAAM,CAAC,cAAc,CAAC,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE;QACd,+DAA+D;QAC/D,QAAQ,EAAE,GAAG,CAAC;QACd,oEAAoE;QACpE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;KAC1B,CAAC;IACF;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,EAAE,gBAAgB,GAAG,SAAS,gBAAgB,EAAE,CAAC;CAC3D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,QAAQ,CAAC,mBAAmB,CAAC,CA0B/B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ManualDatasetSelection, Pipeline, } from '@lde/pipeline';
|
|
2
2
|
import { searchIndexWriter } from './search-index-writer.js';
|
|
3
|
-
import { searchStages, selectByClass } from './search-stages.js';
|
|
3
|
+
import { registrySource, searchStages, selectByClass, } from './search-stages.js';
|
|
4
4
|
/**
|
|
5
5
|
* Wire the common **object-grain** search indexer and return the ready-to-run
|
|
6
6
|
* {@link Pipeline}: one projecting stage per {@link RootType} in the schema,
|
|
@@ -35,7 +35,11 @@ import { searchStages, selectByClass } from './search-stages.js';
|
|
|
35
35
|
* owns no capability of its own.
|
|
36
36
|
*/
|
|
37
37
|
export function searchIndexerPipeline(options) {
|
|
38
|
-
const { schema, datasets } = options;
|
|
38
|
+
const { schema, datasets, registryTypes } = options;
|
|
39
|
+
const fromRegistry = registryTypeNames(schema, registryTypes?.names);
|
|
40
|
+
const sourceFor = registryTypes === undefined
|
|
41
|
+
? undefined
|
|
42
|
+
: registrySource(registryTypes.endpoint);
|
|
39
43
|
return new Pipeline({
|
|
40
44
|
datasetSelector: Array.isArray(datasets)
|
|
41
45
|
? new ManualDatasetSelection(datasets)
|
|
@@ -47,6 +51,7 @@ export function searchIndexerPipeline(options) {
|
|
|
47
51
|
searchType,
|
|
48
52
|
rootVariable: 'root',
|
|
49
53
|
itemSelector: selectByClass(searchType),
|
|
54
|
+
sourceFor: fromRegistry.has(searchType.name) ? sourceFor : undefined,
|
|
50
55
|
})),
|
|
51
56
|
}),
|
|
52
57
|
writers: searchIndexWriter({ schema, writerFor: options.writerFor }),
|
|
@@ -55,3 +60,22 @@ export function searchIndexerPipeline(options) {
|
|
|
55
60
|
reporter: options.reporter,
|
|
56
61
|
});
|
|
57
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* The declared registry-sourced type names, validated against the schema. An
|
|
65
|
+
* unrecognised name is a configuration mistake that would otherwise be silent –
|
|
66
|
+
* the type would read the dataset’s distribution, find no dataset description
|
|
67
|
+
* there, and ship an empty collection – so it throws at wiring time.
|
|
68
|
+
*/
|
|
69
|
+
function registryTypeNames(schema, declaredNames) {
|
|
70
|
+
const names = new Set(declaredNames ?? []);
|
|
71
|
+
const declared = new Set([...schema.values()].map((searchType) => searchType.name));
|
|
72
|
+
const unknown = [...names].filter((name) => !declared.has(name));
|
|
73
|
+
if (unknown.length > 0) {
|
|
74
|
+
throw new Error(`Unknown registry root type(s) ${unknown
|
|
75
|
+
.map((name) => `“${name}”`)
|
|
76
|
+
.join(', ')}; the schema declares ${[...declared]
|
|
77
|
+
.map((name) => `“${name}”`)
|
|
78
|
+
.join(', ')}.`);
|
|
79
|
+
}
|
|
80
|
+
return names;
|
|
81
|
+
}
|
package/dist/search-stages.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Stage, type ItemSelector, type StageReaders } from '@lde/pipeline';
|
|
1
|
+
import { Stage, type ItemSelector, type StageOptions, type StageReaders } from '@lde/pipeline';
|
|
2
2
|
import { type RootType, type SearchSchema } from '@lde/search';
|
|
3
3
|
import type { TypedSearchDocument } from './typed-search-document.js';
|
|
4
4
|
/** One root type’s stage in a search pipeline. */
|
|
@@ -34,6 +34,13 @@ export interface SearchStageType {
|
|
|
34
34
|
* readers, or attach transforms.
|
|
35
35
|
*/
|
|
36
36
|
readers?: StageReaders;
|
|
37
|
+
/**
|
|
38
|
+
* Where this type’s stage reads, when that is not the dataset’s own
|
|
39
|
+
* distribution – see {@link StageOptions.sourceFor}. {@link registrySource}
|
|
40
|
+
* builds the one that matters here: a root type described by the **dataset
|
|
41
|
+
* registry** rather than by the dataset’s data.
|
|
42
|
+
*/
|
|
43
|
+
sourceFor?: StageOptions<TypedSearchDocument>['sourceFor'];
|
|
37
44
|
/**
|
|
38
45
|
* Roots (and so documents) per batch – the memory bound. Under a root-bound
|
|
39
46
|
* selector it moves memory and request count, never output.
|
|
@@ -94,4 +101,44 @@ export declare function searchStages(options: SearchStagesOptions): Stage<TypedS
|
|
|
94
101
|
* SPARQL reader).
|
|
95
102
|
*/
|
|
96
103
|
export declare function selectByClass(searchType: RootType, rootVariable?: string): ItemSelector;
|
|
104
|
+
/**
|
|
105
|
+
* A {@link SearchStageType.sourceFor} that reads a root type from the **dataset
|
|
106
|
+
* registry** instead of from the dataset’s own data – the endpoint fixed,
|
|
107
|
+
* scoped to the graph the dataset in hand names.
|
|
108
|
+
*
|
|
109
|
+
* A dataset’s description is governed by a different application profile from
|
|
110
|
+
* the objects it contains, and it lives in the register, not in the
|
|
111
|
+
* distribution: registering a dataset *is* submitting a description, so the
|
|
112
|
+
* register is the one source that covers every dataset a pipeline can select.
|
|
113
|
+
* Nothing obliges a publisher to ship a description of the dataset in its own
|
|
114
|
+
* dump.
|
|
115
|
+
*
|
|
116
|
+
* The graph scoping is what keeps the stage per-dataset. A register holds every
|
|
117
|
+
* registration, so an unscoped stage would index the whole catalogue for each
|
|
118
|
+
* dataset processed; scoped, each pass sees exactly the one registration – and
|
|
119
|
+
* the roots a `selectByClass` finds inside that graph are that dataset’s own.
|
|
120
|
+
* It presumes the register names each registration’s graph after the dataset
|
|
121
|
+
* IRI, which is how a DCAT register that crawls per registration stores it (the
|
|
122
|
+
* NDE Dataset Register does so for every registration it holds).
|
|
123
|
+
*
|
|
124
|
+
* Routing is deployment topology, deliberately kept out of the
|
|
125
|
+
* {@link SearchType}: a type is defined by its `class`, not by where its
|
|
126
|
+
* triples come from, so the same declaration serves a deployment that sources
|
|
127
|
+
* it differently.
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* searchStages({
|
|
131
|
+
* schema,
|
|
132
|
+
* types: [...schema.values()].map((searchType) => ({
|
|
133
|
+
* searchType,
|
|
134
|
+
* rootVariable: 'root',
|
|
135
|
+
* itemSelector: selectByClass(searchType),
|
|
136
|
+
* sourceFor: registryTypeNames.has(searchType.name)
|
|
137
|
+
* ? registrySource(registryEndpoint)
|
|
138
|
+
* : undefined,
|
|
139
|
+
* })),
|
|
140
|
+
* });
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
export declare function registrySource(endpoint: URL): NonNullable<SearchStageType['sourceFor']>;
|
|
97
144
|
//# sourceMappingURL=search-stages.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-stages.d.ts","sourceRoot":"","sources":["../src/search-stages.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search-stages.d.ts","sourceRoot":"","sources":["../src/search-stages.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEtE,kDAAkD;AAClD,MAAM,WAAW,eAAe;IAC9B;;;;;;OAMG;IACH,UAAU,EAAE,QAAQ,CAAC;IACrB;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,YAAY,EAAE,YAAY,CAAC;IAC3B;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,YAAY,CAAC,mBAAmB,CAAC,CAAC,WAAW,CAAC,CAAC;IAC3D;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wCAAwC;AACxC,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,4DAA4D;IAC5D,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,mBAAmB,GAC3B,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAyD9B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,QAAQ,EACpB,YAAY,SAAS,GACpB,YAAY,CAId;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,GAAG,GACZ,WAAW,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAE3C"}
|
package/dist/search-stages.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Distribution } from '@lde/dataset';
|
|
1
2
|
import { SparqlConstructReader, SparqlItemSelector, Stage, } from '@lde/pipeline';
|
|
2
3
|
import { projectRoots } from '@lde/search';
|
|
3
4
|
import { extractionQueryString } from './extraction.js';
|
|
@@ -39,6 +40,7 @@ export function searchStages(options) {
|
|
|
39
40
|
name: searchType.name,
|
|
40
41
|
readers,
|
|
41
42
|
itemSelector: type.itemSelector,
|
|
43
|
+
sourceFor: type.sourceFor,
|
|
42
44
|
batchSize: type.batchSize,
|
|
43
45
|
maxConcurrency: type.maxConcurrency,
|
|
44
46
|
queueCapacity: type.queueCapacity,
|
|
@@ -86,3 +88,45 @@ export function selectByClass(searchType, rootVariable = 'root') {
|
|
|
86
88
|
query: `SELECT ?${rootVariable} WHERE { ?${rootVariable} a <${searchType.class}> FILTER(!isBlank(?${rootVariable})) }`,
|
|
87
89
|
});
|
|
88
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* A {@link SearchStageType.sourceFor} that reads a root type from the **dataset
|
|
93
|
+
* registry** instead of from the dataset’s own data – the endpoint fixed,
|
|
94
|
+
* scoped to the graph the dataset in hand names.
|
|
95
|
+
*
|
|
96
|
+
* A dataset’s description is governed by a different application profile from
|
|
97
|
+
* the objects it contains, and it lives in the register, not in the
|
|
98
|
+
* distribution: registering a dataset *is* submitting a description, so the
|
|
99
|
+
* register is the one source that covers every dataset a pipeline can select.
|
|
100
|
+
* Nothing obliges a publisher to ship a description of the dataset in its own
|
|
101
|
+
* dump.
|
|
102
|
+
*
|
|
103
|
+
* The graph scoping is what keeps the stage per-dataset. A register holds every
|
|
104
|
+
* registration, so an unscoped stage would index the whole catalogue for each
|
|
105
|
+
* dataset processed; scoped, each pass sees exactly the one registration – and
|
|
106
|
+
* the roots a `selectByClass` finds inside that graph are that dataset’s own.
|
|
107
|
+
* It presumes the register names each registration’s graph after the dataset
|
|
108
|
+
* IRI, which is how a DCAT register that crawls per registration stores it (the
|
|
109
|
+
* NDE Dataset Register does so for every registration it holds).
|
|
110
|
+
*
|
|
111
|
+
* Routing is deployment topology, deliberately kept out of the
|
|
112
|
+
* {@link SearchType}: a type is defined by its `class`, not by where its
|
|
113
|
+
* triples come from, so the same declaration serves a deployment that sources
|
|
114
|
+
* it differently.
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* searchStages({
|
|
118
|
+
* schema,
|
|
119
|
+
* types: [...schema.values()].map((searchType) => ({
|
|
120
|
+
* searchType,
|
|
121
|
+
* rootVariable: 'root',
|
|
122
|
+
* itemSelector: selectByClass(searchType),
|
|
123
|
+
* sourceFor: registryTypeNames.has(searchType.name)
|
|
124
|
+
* ? registrySource(registryEndpoint)
|
|
125
|
+
* : undefined,
|
|
126
|
+
* })),
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function registrySource(endpoint) {
|
|
131
|
+
return (dataset) => Distribution.sparql(endpoint, dataset.iri.toString());
|
|
132
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search-pipeline",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.2",
|
|
4
4
|
"description": "Search indexing as an @lde/pipeline instance: a Writer<Quad> that applies the @lde/search projection to extracted RDF and fans each document out to the transactional engine writer for its type's collection. Glue between the pipeline quad world and the search-engine document world; owns no projection or engine logic itself.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "git+https://github.com/ldelements/lde.git",
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"tslib": "^2.3.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@lde/search-typesense": "^0.18.
|
|
35
|
+
"@lde/search-typesense": "^0.18.2",
|
|
36
36
|
"@rdfjs/types": "^2.0.1",
|
|
37
|
-
"n3": "^2.1.
|
|
37
|
+
"n3": "^2.1.2",
|
|
38
38
|
"testcontainers": "^12.0.3",
|
|
39
39
|
"typesense": "^3.0.6"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@lde/dataset": "^0.7.9",
|
|
43
|
-
"@lde/pipeline": "^0.35.
|
|
43
|
+
"@lde/pipeline": "^0.35.6"
|
|
44
44
|
}
|
|
45
45
|
}
|