@lde/search-pipeline 0.12.1 → 0.12.3

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 CHANGED
@@ -34,6 +34,62 @@ The division of labour ([ADR 6](../../docs/decisions/0006-make-the-writer-transa
34
34
 
35
35
  So a search pipeline is **one terminal, N stages**: `new Pipeline<TypedSearchDocument>({ datasetSelector, stages: searchStages(...), writers: searchIndexWriter(...) })`.
36
36
 
37
+ ## Quick start: `searchIndexerPipeline`
38
+
39
+ For the common **object grain** – index every IRI-identified instance of each
40
+ root type’s source class – `searchIndexerPipeline` wires that whole composition
41
+ and returns the ready-to-run `Pipeline`. It generates one stage per root type
42
+ in the schema, each selecting the type’s non-blank roots by class
43
+ (`selectByClass`; a blank node has no stable document key, so it can never
44
+ become a document), extracting with the schema-generated CONSTRUCT, and routing
45
+ every document to the engine writer for its type’s collection. The consumer
46
+ supplies only the domain (the schema, which datasets) and the deployment shell
47
+ (the engine writer, the SPARQL/import adapter):
48
+
49
+ ```typescript
50
+ import { searchIndexerPipeline } from '@lde/search-pipeline';
51
+ import {
52
+ FileProvenanceStore,
53
+ ImportResolver,
54
+ SparqlDistributionResolver,
55
+ } from '@lde/pipeline';
56
+ import { ConsoleReporter } from '@lde/pipeline-console-reporter';
57
+ import { createQlever } from '@lde/sparql-qlever';
58
+ import { InPlaceRebuild } from '@lde/search-typesense';
59
+
60
+ const pipeline = searchIndexerPipeline({
61
+ schema,
62
+ datasets,
63
+ // Import each dataset’s data dump into a local QLever and query that.
64
+ distributionResolver: new ImportResolver(new SparqlDistributionResolver(), {
65
+ ...createQlever({ mode: 'docker', image: 'adfreiburg/qlever:latest' }),
66
+ strategy: 'import',
67
+ }),
68
+ writerFor: (searchType) => new InPlaceRebuild(typesenseClient, searchType),
69
+ // Optional: skip datasets whose source and pipeline version are unchanged.
70
+ provenanceStore: new FileProvenanceStore({ path: 'data/provenance.json' }),
71
+ pipelineVersion: '1',
72
+ reporter: new ConsoleReporter(),
73
+ });
74
+ await pipeline.run();
75
+ ```
76
+
77
+ Each role in that wiring maps to a package:
78
+
79
+ | Role | Package |
80
+ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
81
+ | Dataset selection | [`@lde/pipeline`](../pipeline) – `Dataset[]` directly, or a `DatasetSelector` such as `RegistrySelector` |
82
+ | Distribution resolution and import | [`@lde/pipeline`](../pipeline) `ImportResolver` + [`@lde/sparql-qlever`](../sparql-qlever) `createQlever` (the concrete [`@lde/sparql-server`](../sparql-server)/[`@lde/sparql-importer`](../sparql-importer) adapter) |
83
+ | Root selection, extraction, projection | this package (`searchStages` over [`@lde/search`](../search)) |
84
+ | Engine writer, one collection per type | [`@lde/search-typesense`](../search-typesense) – `InPlaceRebuild` or `BlueGreenRebuild` |
85
+ | Provenance (skip-unchanged) | [`@lde/pipeline`](../pipeline) – `FileProvenanceStore`, or a triplestore-backed store |
86
+ | Reporting | [`@lde/pipeline-console-reporter`](../pipeline-console-reporter) `ConsoleReporter` |
87
+
88
+ A deployment that needs more – a bespoke root selector (where the entry point
89
+ is a domain fact, not a class), per-stage tuning, non-SPARQL readers, or
90
+ quad-level plugins – composes the parts directly, as below; the convenience
91
+ owns no capability of its own.
92
+
37
93
  ## Usage
38
94
 
39
95
  ```typescript
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { searchIndexerPipeline } from './search-indexer-pipeline.js';
2
+ export type { SearchIndexerPipelineOptions } from './search-indexer-pipeline.js';
1
3
  export { searchStages, selectByClass } from './search-stages.js';
2
4
  export type { SearchStagesOptions, SearchStageType } from './search-stages.js';
3
5
  export { extractionQuery, extractionQueryString } from './extraction.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,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"}
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,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,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,3 +1,4 @@
1
+ export { searchIndexerPipeline } from './search-indexer-pipeline.js';
1
2
  export { searchStages, selectByClass } from './search-stages.js';
2
3
  export { extractionQuery, extractionQueryString } from './extraction.js';
3
4
  export { searchIndexWriter } from './search-index-writer.js';
@@ -0,0 +1,86 @@
1
+ import type { Dataset } from '@lde/dataset';
2
+ import { Pipeline, type DatasetSelector, type DistributionResolver, type ProgressReporter, type ProvenanceStore, type Writer } from '@lde/pipeline';
3
+ import type { RootType, SearchDocument, SearchSchema } from '@lde/search';
4
+ import type { TypedSearchDocument } from './typed-search-document.js';
5
+ /** Options for {@link searchIndexerPipeline}. */
6
+ export interface SearchIndexerPipelineOptions {
7
+ /**
8
+ * The declarative schema driving the indexer: one stage and one engine
9
+ * collection per {@link RootType} in it. Reference Types are absent from
10
+ * `schema.values()`, so none ever earns a stage or a collection.
11
+ */
12
+ schema: SearchSchema;
13
+ /**
14
+ * Which datasets to index – the deployment’s domain fact. Pass the
15
+ * {@link Dataset}s directly, or a {@link DatasetSelector} (e.g. a
16
+ * `RegistrySelector`) when selection is dynamic.
17
+ */
18
+ datasets: Dataset[] | DatasetSelector;
19
+ /**
20
+ * How each dataset’s data becomes queryable – the deployment’s engine
21
+ * choice. Typically an `ImportResolver` wrapping a
22
+ * `SparqlDistributionResolver` with a `@lde/sparql-qlever` `createQlever`
23
+ * import path, so data-dump distributions are imported into a local
24
+ * endpoint. Defaults to the {@link Pipeline} default (a bare
25
+ * `SparqlDistributionResolver`), which serves only datasets that publish a
26
+ * live SPARQL endpoint.
27
+ */
28
+ distributionResolver?: DistributionResolver;
29
+ /**
30
+ * The engine writer that owns a given root type’s collection – e.g. a
31
+ * `@lde/search-typesense` `InPlaceRebuild` or `BlueGreenRebuild` bound to
32
+ * that type. Called once per {@link RootType} in the schema.
33
+ */
34
+ writerFor: (searchType: RootType) => Writer<SearchDocument>;
35
+ /**
36
+ * Optional per-dataset processing memory: skip a dataset whose source
37
+ * fingerprint and {@link pipelineVersion} both match the stored record.
38
+ * Requires {@link pipelineVersion}.
39
+ */
40
+ provenanceStore?: ProvenanceStore;
41
+ /**
42
+ * Opaque, consumer-declared version of the indexer’s output-affecting logic
43
+ * (schema, projection). Required when {@link provenanceStore} is set – a
44
+ * skip-enabled pipeline with no version would silently freeze.
45
+ */
46
+ pipelineVersion?: string;
47
+ /**
48
+ * Observer(s) of pipeline lifecycle events, e.g. a
49
+ * `@lde/pipeline-console-reporter` `ConsoleReporter`.
50
+ */
51
+ reporter?: ProgressReporter | readonly ProgressReporter[];
52
+ }
53
+ /**
54
+ * Wire the common **object-grain** search indexer and return the ready-to-run
55
+ * {@link Pipeline}: one projecting stage per {@link RootType} in the schema,
56
+ * each selecting the type’s roots by its source class with blank-node subjects
57
+ * excluded ({@link selectByClass} – a blank node has no stable document key),
58
+ * extracting with the schema-generated CONSTRUCT, and projecting inside the
59
+ * batch; plus the single {@link searchIndexWriter} terminal routing each
60
+ * document to the engine writer for its type’s collection.
61
+ *
62
+ * The consumer supplies only the domain and the deployment shell: the schema,
63
+ * which datasets, the engine writer per type, and (optionally) the
64
+ * SPARQL/import adapter, provenance and reporting.
65
+ *
66
+ * ```ts
67
+ * const pipeline = searchIndexerPipeline({
68
+ * schema,
69
+ * datasets,
70
+ * distributionResolver: new ImportResolver(new SparqlDistributionResolver(), {
71
+ * ...createQlever({ mode: 'docker', image: 'adfreiburg/qlever:latest' }),
72
+ * strategy: 'import',
73
+ * }),
74
+ * writerFor: (searchType) => new InPlaceRebuild(typesenseClient, searchType),
75
+ * });
76
+ * await pipeline.run();
77
+ * ```
78
+ *
79
+ * A deployment that needs more – a bespoke root selector (the entry point is a
80
+ * domain fact, not a class), per-stage tuning (`batchSize`, `maxConcurrency`),
81
+ * non-SPARQL readers, or quad-level plugins – composes {@link searchStages},
82
+ * {@link searchIndexWriter} and {@link Pipeline} directly; this convenience
83
+ * owns no capability of its own.
84
+ */
85
+ export declare function searchIndexerPipeline(options: SearchIndexerPipelineOptions): Pipeline<TypedSearchDocument>;
86
+ //# sourceMappingURL=search-indexer-pipeline.d.ts.map
@@ -0,0 +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;AAG1E,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;;;;OAIG;IACH,SAAS,EAAE,CAAC,UAAU,EAAE,QAAQ,KAAK,MAAM,CAAC,cAAc,CAAC,CAAC;IAC5D;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,QAAQ,CAAC,mBAAmB,CAAC,CAoB/B"}
@@ -0,0 +1,56 @@
1
+ import { ManualDatasetSelection, Pipeline, } from '@lde/pipeline';
2
+ import { searchIndexWriter } from './search-index-writer.js';
3
+ import { searchStages, selectByClass } from './search-stages.js';
4
+ /**
5
+ * Wire the common **object-grain** search indexer and return the ready-to-run
6
+ * {@link Pipeline}: one projecting stage per {@link RootType} in the schema,
7
+ * each selecting the type’s roots by its source class with blank-node subjects
8
+ * excluded ({@link selectByClass} – a blank node has no stable document key),
9
+ * extracting with the schema-generated CONSTRUCT, and projecting inside the
10
+ * batch; plus the single {@link searchIndexWriter} terminal routing each
11
+ * document to the engine writer for its type’s collection.
12
+ *
13
+ * The consumer supplies only the domain and the deployment shell: the schema,
14
+ * which datasets, the engine writer per type, and (optionally) the
15
+ * SPARQL/import adapter, provenance and reporting.
16
+ *
17
+ * ```ts
18
+ * const pipeline = searchIndexerPipeline({
19
+ * schema,
20
+ * datasets,
21
+ * distributionResolver: new ImportResolver(new SparqlDistributionResolver(), {
22
+ * ...createQlever({ mode: 'docker', image: 'adfreiburg/qlever:latest' }),
23
+ * strategy: 'import',
24
+ * }),
25
+ * writerFor: (searchType) => new InPlaceRebuild(typesenseClient, searchType),
26
+ * });
27
+ * await pipeline.run();
28
+ * ```
29
+ *
30
+ * A deployment that needs more – a bespoke root selector (the entry point is a
31
+ * domain fact, not a class), per-stage tuning (`batchSize`, `maxConcurrency`),
32
+ * non-SPARQL readers, or quad-level plugins – composes {@link searchStages},
33
+ * {@link searchIndexWriter} and {@link Pipeline} directly; this convenience
34
+ * owns no capability of its own.
35
+ */
36
+ export function searchIndexerPipeline(options) {
37
+ const { schema, datasets } = options;
38
+ return new Pipeline({
39
+ datasetSelector: Array.isArray(datasets)
40
+ ? new ManualDatasetSelection(datasets)
41
+ : datasets,
42
+ distributionResolver: options.distributionResolver,
43
+ stages: searchStages({
44
+ schema,
45
+ types: [...schema.values()].map((searchType) => ({
46
+ searchType,
47
+ rootVariable: 'root',
48
+ itemSelector: selectByClass(searchType),
49
+ })),
50
+ }),
51
+ writers: searchIndexWriter({ schema, writerFor: options.writerFor }),
52
+ provenanceStore: options.provenanceStore,
53
+ pipelineVersion: options.pipelineVersion,
54
+ reporter: options.reporter,
55
+ });
56
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/search-pipeline",
3
- "version": "0.12.1",
3
+ "version": "0.12.3",
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,7 +32,7 @@
32
32
  "tslib": "^2.3.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@lde/search-typesense": "^0.15.1",
35
+ "@lde/search-typesense": "^0.15.3",
36
36
  "@rdfjs/types": "^2.0.1",
37
37
  "n3": "^2.1.1",
38
38
  "testcontainers": "^12.0.3",
@@ -40,6 +40,6 @@
40
40
  },
41
41
  "peerDependencies": {
42
42
  "@lde/dataset": "^0.7.8",
43
- "@lde/pipeline": "^0.35.0"
43
+ "@lde/pipeline": "^0.35.2"
44
44
  }
45
45
  }