@lde/search-pipeline 0.3.1 → 0.4.0
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 +71 -32
- package/dist/search-index-writer.d.ts +38 -14
- package/dist/search-index-writer.d.ts.map +1 -1
- package/dist/search-index-writer.js +118 -20
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -11,11 +11,13 @@ The division of labour ([ADR 6](../../docs/decisions/0006-make-the-writer-transa
|
|
|
11
11
|
- [`@lde/search`](../search) owns the engine-agnostic projection (framed
|
|
12
12
|
document + field model) and stays pipeline-free;
|
|
13
13
|
- `@lde/search-<engine>` (e.g. [`@lde/search-typesense`](../search-typesense))
|
|
14
|
-
is the engine adapter: a transactional `Writer`
|
|
15
|
-
documents, owning the run lifecycle (Blue/green alias swap
|
|
16
|
-
sweeps, cross-pod lock);
|
|
17
|
-
- **this package** composes them: `searchIndexWriter` is the one
|
|
18
|
-
|
|
14
|
+
is the engine adapter: a transactional, **single-collection** `Writer`
|
|
15
|
+
consuming projected documents, owning the run lifecycle (Blue/green alias swap
|
|
16
|
+
or In-place sweeps, cross-pod lock);
|
|
17
|
+
- **this package** composes them: `searchIndexWriter` is the one type-changing
|
|
18
|
+
step (quad → document), shared across engines, and – since one schema declares
|
|
19
|
+
several root types – it fans each document out to the engine writer for **its**
|
|
20
|
+
type’s collection ([ADR 9](../../docs/decisions/0009-route-a-whole-schema-projection-to-per-type-collections.md)).
|
|
19
21
|
|
|
20
22
|
## Usage
|
|
21
23
|
|
|
@@ -25,20 +27,41 @@ import { searchSchema } from '@lde/search';
|
|
|
25
27
|
import { BlueGreenRebuild } from '@lde/search-typesense';
|
|
26
28
|
import { searchIndexWriter } from '@lde/search-pipeline';
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
30
|
+
// One schema, several root types: the `datasets` catalog plus the Organization
|
|
31
|
+
// label collection its references resolve against.
|
|
32
|
+
const schema = searchSchema(
|
|
33
|
+
{
|
|
34
|
+
name: 'Dataset',
|
|
35
|
+
type: 'http://www.w3.org/ns/dcat#Dataset',
|
|
36
|
+
fields: [
|
|
37
|
+
{
|
|
38
|
+
name: 'title',
|
|
39
|
+
kind: 'text',
|
|
40
|
+
path: 'http://purl.org/dc/terms/title',
|
|
41
|
+
locales: ['und'],
|
|
42
|
+
output: true,
|
|
43
|
+
searchable: { weight: 5 },
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'Organization',
|
|
49
|
+
type: 'http://xmlns.com/foaf/0.1/Organization',
|
|
50
|
+
fields: [
|
|
51
|
+
{
|
|
52
|
+
name: 'label',
|
|
53
|
+
kind: 'text',
|
|
54
|
+
path: 'http://xmlns.com/foaf/0.1/name',
|
|
55
|
+
locales: ['und'],
|
|
56
|
+
output: true,
|
|
57
|
+
searchable: { weight: 1 },
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
// Each type maps to its own collection: an independent blue/green rebuild.
|
|
64
|
+
const collectionName = { Dataset: 'datasets', Organization: 'organizations' };
|
|
42
65
|
|
|
43
66
|
const pipeline = new Pipeline({
|
|
44
67
|
datasetSelector,
|
|
@@ -50,13 +73,10 @@ const pipeline = new Pipeline({
|
|
|
50
73
|
],
|
|
51
74
|
writers: searchIndexWriter({
|
|
52
75
|
schema,
|
|
53
|
-
|
|
54
|
-
typesenseClient,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
name: 'datasets',
|
|
58
|
-
},
|
|
59
|
-
),
|
|
76
|
+
writerFor: (searchType) =>
|
|
77
|
+
new BlueGreenRebuild(typesenseClient, searchType, {
|
|
78
|
+
name: collectionName[searchType.name],
|
|
79
|
+
}),
|
|
60
80
|
}),
|
|
61
81
|
});
|
|
62
82
|
|
|
@@ -64,12 +84,31 @@ await pipeline.run();
|
|
|
64
84
|
```
|
|
65
85
|
|
|
66
86
|
Each dataset’s extracted CONSTRUCT quads are buffered until the dataset
|
|
67
|
-
completes, then
|
|
68
|
-
|
|
69
|
-
engine
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
completes, then projected once over the **whole** schema (`@lde/search`’s
|
|
88
|
+
`projectGraph`) into one mixed, type-tagged stream, and each document is
|
|
89
|
+
dispatched to the engine run for its type’s collection – before the engine acts
|
|
90
|
+
on the dataset’s completion, so an In-place stale sweep never races its own
|
|
91
|
+
documents. The run lifecycle (run context, per-dataset flush outcome,
|
|
92
|
+
commit/abort) passes through unchanged: the engine writer’s update mode governs,
|
|
93
|
+
and the pipeline never branches on it, nor on how many collections there are.
|
|
94
|
+
|
|
95
|
+
## Per-collection isolation
|
|
96
|
+
|
|
97
|
+
Each root type is an independent engine run – its own collection, alias and
|
|
98
|
+
cross-pod lock – so the collections commit, sweep and fail in isolation:
|
|
99
|
+
|
|
100
|
+
- a type whose projection is empty this run affects only its own collection,
|
|
101
|
+
never another’s – in particular the `datasets` index still goes live;
|
|
102
|
+
- `commit` finalizes every collection independently and, if any fails, throws an
|
|
103
|
+
`AggregateError` _after_ attempting them all, so a non-critical
|
|
104
|
+
label-collection failure never blocks the collections that did commit, while
|
|
105
|
+
the failure is still surfaced (the run is marked failed);
|
|
106
|
+
- because the pipeline aborts a run whose `commit` throws, `abort` finalizes only
|
|
107
|
+
the collections that did **not** already go live (aborting a committed
|
|
108
|
+
blue/green rebuild would drop its now-live collection), dropping the half-built
|
|
109
|
+
ones and releasing their locks.
|
|
110
|
+
|
|
111
|
+
See [ADR 9](../../docs/decisions/0009-route-a-whole-schema-projection-to-per-type-collections.md).
|
|
73
112
|
|
|
74
113
|
## Memory
|
|
75
114
|
|
|
@@ -1,31 +1,55 @@
|
|
|
1
1
|
import type { Quad } from '@rdfjs/types';
|
|
2
2
|
import type { Writer } from '@lde/pipeline';
|
|
3
|
-
import { type SearchDocument, type SearchSchema } from '@lde/search';
|
|
3
|
+
import { type SearchDocument, type SearchSchema, type SearchType } from '@lde/search';
|
|
4
4
|
/** Options for {@link searchIndexWriter}. */
|
|
5
5
|
export interface SearchIndexWriterOptions {
|
|
6
6
|
/**
|
|
7
7
|
* The declarative schema driving the projection: one {@link SearchType} per
|
|
8
|
-
* root type, each mapping framed RDF to flat search-document fields.
|
|
8
|
+
* root type, each mapping framed RDF to flat search-document fields. The
|
|
9
|
+
* writer opens one engine run per type in it.
|
|
9
10
|
*/
|
|
10
11
|
schema: SearchSchema;
|
|
11
12
|
/**
|
|
12
|
-
* The engine
|
|
13
|
-
* `@lde/search-typesense
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* The engine writer that owns a given root type’s collection – e.g. a
|
|
14
|
+
* `@lde/search-typesense` `BlueGreenRebuild` bound to that type and the
|
|
15
|
+
* collection name it keeps its alias on. Called once per {@link SearchType}
|
|
16
|
+
* in the schema when the writer is built.
|
|
17
|
+
*
|
|
18
|
+
* A single-collection deployment returns one writer for its one type; a
|
|
19
|
+
* multi-collection deployment (the Dataset Register’s `datasets` plus its
|
|
20
|
+
* Organization / Class / TerminologySource label collections) returns a
|
|
21
|
+
* distinct writer per type, each an independent blue/green rebuild with its
|
|
22
|
+
* own collection, alias and cross-pod lock. The projection is whole-schema
|
|
23
|
+
* either way; the per-collection fan-out is this writer’s job.
|
|
16
24
|
*/
|
|
17
|
-
|
|
25
|
+
writerFor: (searchType: SearchType) => Writer<SearchDocument>;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
20
|
-
* The projection step of a search-indexing pipeline, as a quad `Writer
|
|
21
|
-
* turns each dataset’s extracted CONSTRUCT
|
|
22
|
-
* documents ({@link projectGraph}: frame by
|
|
23
|
-
* with its type’s declaration) and
|
|
24
|
-
* the
|
|
25
|
-
*
|
|
28
|
+
* The projection step of a search-indexing pipeline, as a quad `Writer`, fanned
|
|
29
|
+
* out across a type’s collections. It turns each dataset’s extracted CONSTRUCT
|
|
30
|
+
* quads into engine-agnostic search documents ({@link projectGraph}: frame by
|
|
31
|
+
* root type, then project each node with its type’s declaration) and dispatches
|
|
32
|
+
* each document to the engine run for **its** type. This is the one
|
|
33
|
+
* type-changing step (quad → document), shared across engines – which is why it
|
|
34
|
+
* lives here and not inside an engine adapter.
|
|
35
|
+
*
|
|
36
|
+
* Each root type is an independent engine run (its own collection, alias and
|
|
37
|
+
* lock), so the collections commit, sweep and fail in isolation:
|
|
38
|
+
*
|
|
39
|
+
* - a type whose projection is empty this run affects only its own collection,
|
|
40
|
+
* never another’s – in particular the `datasets` index still goes live;
|
|
41
|
+
* - `commit` finalizes every collection independently and, if any fails, throws
|
|
42
|
+
* an `AggregateError` *after* attempting them all, so a non-critical
|
|
43
|
+
* label-collection failure never blocks the collections that did commit,
|
|
44
|
+
* while the failure is still surfaced (the pipeline marks the run failed).
|
|
45
|
+
* Because the pipeline then calls {@link RunWriter.abort}, `abort` finalizes
|
|
46
|
+
* only the collections that did **not** already go live – aborting a
|
|
47
|
+
* committed blue/green rebuild would drop its now-live collection;
|
|
48
|
+
* - `abort` (a run failure, or a partial commit) drops every half-built
|
|
49
|
+
* collection that has not committed and leaves the live ones untouched.
|
|
26
50
|
*
|
|
27
51
|
* A dataset’s quads are buffered until its flush and projected then, so the
|
|
28
|
-
* documents land before
|
|
52
|
+
* documents land before every engine acts on the dataset’s completion (e.g. an
|
|
29
53
|
* In-place stale sweep). Memory is bounded by one dataset’s extraction, and
|
|
30
54
|
* released at each flush – nothing accumulates across datasets. Streaming
|
|
31
55
|
* bounded entity batches *within* one huge dataset needs the two-level
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-index-writer.d.ts","sourceRoot":"","sources":["../src/search-index-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAIV,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,YAAY,
|
|
1
|
+
{"version":3,"file":"search-index-writer.d.ts","sourceRoot":"","sources":["../src/search-index-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAIV,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAErB,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,SAAS,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC,cAAc,CAAC,CAAC;CAC/D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,wBAAwB,GAChC,MAAM,CAAC,IAAI,CAAC,CA2Id"}
|
|
@@ -1,34 +1,90 @@
|
|
|
1
1
|
import { projectGraph, } from '@lde/search';
|
|
2
2
|
/**
|
|
3
|
-
* The projection step of a search-indexing pipeline, as a quad `Writer
|
|
4
|
-
* turns each dataset’s extracted CONSTRUCT
|
|
5
|
-
* documents ({@link projectGraph}: frame by
|
|
6
|
-
* with its type’s declaration) and
|
|
7
|
-
* the
|
|
8
|
-
*
|
|
3
|
+
* The projection step of a search-indexing pipeline, as a quad `Writer`, fanned
|
|
4
|
+
* out across a type’s collections. It turns each dataset’s extracted CONSTRUCT
|
|
5
|
+
* quads into engine-agnostic search documents ({@link projectGraph}: frame by
|
|
6
|
+
* root type, then project each node with its type’s declaration) and dispatches
|
|
7
|
+
* each document to the engine run for **its** type. This is the one
|
|
8
|
+
* type-changing step (quad → document), shared across engines – which is why it
|
|
9
|
+
* lives here and not inside an engine adapter.
|
|
10
|
+
*
|
|
11
|
+
* Each root type is an independent engine run (its own collection, alias and
|
|
12
|
+
* lock), so the collections commit, sweep and fail in isolation:
|
|
13
|
+
*
|
|
14
|
+
* - a type whose projection is empty this run affects only its own collection,
|
|
15
|
+
* never another’s – in particular the `datasets` index still goes live;
|
|
16
|
+
* - `commit` finalizes every collection independently and, if any fails, throws
|
|
17
|
+
* an `AggregateError` *after* attempting them all, so a non-critical
|
|
18
|
+
* label-collection failure never blocks the collections that did commit,
|
|
19
|
+
* while the failure is still surfaced (the pipeline marks the run failed).
|
|
20
|
+
* Because the pipeline then calls {@link RunWriter.abort}, `abort` finalizes
|
|
21
|
+
* only the collections that did **not** already go live – aborting a
|
|
22
|
+
* committed blue/green rebuild would drop its now-live collection;
|
|
23
|
+
* - `abort` (a run failure, or a partial commit) drops every half-built
|
|
24
|
+
* collection that has not committed and leaves the live ones untouched.
|
|
9
25
|
*
|
|
10
26
|
* A dataset’s quads are buffered until its flush and projected then, so the
|
|
11
|
-
* documents land before
|
|
27
|
+
* documents land before every engine acts on the dataset’s completion (e.g. an
|
|
12
28
|
* In-place stale sweep). Memory is bounded by one dataset’s extraction, and
|
|
13
29
|
* released at each flush – nothing accumulates across datasets. Streaming
|
|
14
30
|
* bounded entity batches *within* one huge dataset needs the two-level
|
|
15
31
|
* iteration (dataset → entity-URI batches) and is not implemented yet.
|
|
16
32
|
*/
|
|
17
33
|
export function searchIndexWriter(options) {
|
|
18
|
-
const { schema,
|
|
34
|
+
const { schema, writerFor } = options;
|
|
35
|
+
// One engine writer per root type, built once; each run opens them all. Keyed
|
|
36
|
+
// by the type IRI, which is also how a projected document names its type.
|
|
37
|
+
const writers = new Map([...schema.values()].map((searchType) => [
|
|
38
|
+
searchType.type,
|
|
39
|
+
writerFor(searchType),
|
|
40
|
+
]));
|
|
19
41
|
return {
|
|
20
42
|
async openRun(context) {
|
|
21
|
-
const
|
|
43
|
+
const runs = new Map();
|
|
44
|
+
try {
|
|
45
|
+
for (const [typeIri, writer] of writers) {
|
|
46
|
+
runs.set(typeIri, await writer.openRun(context));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// One engine run failed to open (e.g. its lock is held); roll the
|
|
51
|
+
// already-opened ones back so no collection or lock is left dangling.
|
|
52
|
+
await Promise.allSettled([...runs.values()].map((run) => run.abort(error)));
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
// The collections that have gone live, so `abort` never re-finalizes one
|
|
56
|
+
// (a committed blue/green rebuild’s abort drops its now-live collection).
|
|
57
|
+
const committed = new Set();
|
|
22
58
|
// One buffered pass per dataset, keyed by IRI. The pipeline processes
|
|
23
|
-
// datasets sequentially, but keeping the key explicit makes a write
|
|
24
|
-
//
|
|
59
|
+
// datasets sequentially, but keeping the key explicit makes a write after
|
|
60
|
+
// another dataset's flush safe too.
|
|
25
61
|
const passes = new Map();
|
|
26
62
|
const project = async (pass) => {
|
|
27
63
|
passes.delete(pass.dataset.iri.toString());
|
|
28
64
|
if (pass.quads.length === 0) {
|
|
29
65
|
return;
|
|
30
66
|
}
|
|
31
|
-
|
|
67
|
+
// Whole-schema projection into one mixed stream, split by type here so
|
|
68
|
+
// each type’s documents reach its own collection’s run.
|
|
69
|
+
const byType = new Map();
|
|
70
|
+
for await (const { searchType, document } of projectGraph(pass.quads, schema)) {
|
|
71
|
+
const documents = byType.get(searchType.type);
|
|
72
|
+
if (documents === undefined) {
|
|
73
|
+
byType.set(searchType.type, [document]);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
documents.push(document);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Every yielded type is a schema type, so it has a run; iterate the
|
|
80
|
+
// runs and write each the documents projected for its type (none, for a
|
|
81
|
+
// type absent from this pass).
|
|
82
|
+
for (const [typeIri, run] of runs) {
|
|
83
|
+
const documents = byType.get(typeIri);
|
|
84
|
+
if (documents !== undefined) {
|
|
85
|
+
await run.write(pass.dataset, stream(documents));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
32
88
|
};
|
|
33
89
|
return {
|
|
34
90
|
write: async (dataset, quads) => {
|
|
@@ -47,24 +103,66 @@ export function searchIndexWriter(options) {
|
|
|
47
103
|
if (pass !== undefined) {
|
|
48
104
|
await project(pass);
|
|
49
105
|
}
|
|
50
|
-
|
|
106
|
+
// Flush every collection independently: one collection’s flush failure
|
|
107
|
+
// (a rollback, or an In-place stale sweep) must not skip another’s –
|
|
108
|
+
// the pipeline isolates a flush error per dataset and still commits,
|
|
109
|
+
// so a skipped collection would swap live with a dataset it should
|
|
110
|
+
// have rolled back or swept. Every collection is flushed, not just the
|
|
111
|
+
// ones that received documents this dataset: a collection an earlier
|
|
112
|
+
// run held documents for still needs its sweep to reconcile.
|
|
113
|
+
await settleAll(runs.values(), 'flush', (run) => run.flush?.(dataset, outcome));
|
|
51
114
|
},
|
|
52
115
|
reset: async (dataset) => {
|
|
53
|
-
// Discard the buffered pass so the re-run replaces it, and let
|
|
54
|
-
//
|
|
116
|
+
// Discard the buffered pass so the re-run replaces it, and let every
|
|
117
|
+
// collection’s run discard whatever it already holds for the dataset –
|
|
118
|
+
// independently, so one collection’s reset failure never leaves
|
|
119
|
+
// another holding the discarded pass’s documents into the re-run.
|
|
55
120
|
passes.delete(dataset.iri.toString());
|
|
56
|
-
await run.reset?.(dataset);
|
|
121
|
+
await settleAll(runs.values(), 'reset', (run) => run.reset?.(dataset));
|
|
57
122
|
},
|
|
58
123
|
commit: async () => {
|
|
59
|
-
// Safety net: project passes that were never flushed, so a
|
|
60
|
-
//
|
|
124
|
+
// Safety net: project passes that were never flushed, so a committed
|
|
125
|
+
// run never silently drops written quads.
|
|
61
126
|
for (const pass of [...passes.values()]) {
|
|
62
127
|
await project(pass);
|
|
63
128
|
}
|
|
64
|
-
|
|
129
|
+
// Commit every collection independently, so one failure neither
|
|
130
|
+
// blocks nor wipes another – the `datasets` index goes live even if a
|
|
131
|
+
// label collection cannot. Record each collection that went live, so
|
|
132
|
+
// the abort that follows a failed commit never drops it.
|
|
133
|
+
await settleAll(runs, 'commit', async ([typeIri, run]) => {
|
|
134
|
+
await run.commit();
|
|
135
|
+
committed.add(typeIri);
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
abort: async (error) => {
|
|
139
|
+
// Finalize only the collections that have not gone live: aborting a
|
|
140
|
+
// committed blue/green rebuild would drop its now-live collection.
|
|
141
|
+
// Best-effort – cleanup failures must not mask the original error.
|
|
142
|
+
await Promise.allSettled([...runs]
|
|
143
|
+
.filter(([typeIri]) => !committed.has(typeIri))
|
|
144
|
+
.map(([, run]) => run.abort(error)));
|
|
65
145
|
},
|
|
66
|
-
abort: (error) => run.abort(error),
|
|
67
146
|
};
|
|
68
147
|
},
|
|
69
148
|
};
|
|
70
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Run `operation` on every collection concurrently and independently, so one
|
|
152
|
+
* collection’s failure never skips another’s (a flush’s rollback, a reset’s
|
|
153
|
+
* discard, a commit’s alias swap). Surface the failures together once all have
|
|
154
|
+
* been attempted, as an `AggregateError` – the run is still marked failed, but
|
|
155
|
+
* every collection got its chance to reconcile or go live first.
|
|
156
|
+
*/
|
|
157
|
+
async function settleAll(items, verb, operation) {
|
|
158
|
+
const targets = [...items];
|
|
159
|
+
const outcomes = await Promise.allSettled(targets.map((item) => operation(item)));
|
|
160
|
+
const failures = outcomes.flatMap((outcome) => outcome.status === 'rejected' ? [outcome.reason] : []);
|
|
161
|
+
if (failures.length > 0) {
|
|
162
|
+
throw new AggregateError(failures, `${failures.length} of ${targets.length} search collections failed to ${verb}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** Yield the given documents as an async iterable, like a streaming source. */
|
|
166
|
+
async function* stream(items) {
|
|
167
|
+
yield* items;
|
|
168
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search-pipeline",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Search indexing as an @lde/pipeline instance: a Writer<Quad> that applies the @lde/search projection to extracted RDF and
|
|
3
|
+
"version": "0.4.0",
|
|
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",
|
|
7
7
|
"directory": "packages/search-pipeline"
|
|
@@ -25,12 +25,15 @@
|
|
|
25
25
|
"!**/*.tsbuildinfo"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@lde/search": "^0.
|
|
28
|
+
"@lde/search": "^0.5.0",
|
|
29
29
|
"@rdfjs/types": "^2.0.1",
|
|
30
30
|
"tslib": "^2.3.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"
|
|
33
|
+
"@lde/search-typesense": "^0.7.0",
|
|
34
|
+
"n3": "^2.1.1",
|
|
35
|
+
"testcontainers": "^12.0.3",
|
|
36
|
+
"typesense": "^3.0.6"
|
|
34
37
|
},
|
|
35
38
|
"peerDependencies": {
|
|
36
39
|
"@lde/dataset": "^0.7.8",
|