@lde/search-typesense 0.27.4 → 0.29.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/dist/blue-green-rebuild.d.ts +7 -8
- package/dist/blue-green-rebuild.d.ts.map +1 -1
- package/dist/blue-green-rebuild.js +27 -41
- package/dist/collection-definition.d.ts +17 -12
- package/dist/collection-definition.d.ts.map +1 -1
- package/dist/collection-definition.js +253 -54
- package/dist/documents.d.ts +147 -0
- package/dist/documents.d.ts.map +1 -0
- package/dist/documents.js +529 -0
- package/dist/in-place-rebuild.d.ts +30 -35
- package/dist/in-place-rebuild.d.ts.map +1 -1
- package/dist/in-place-rebuild.js +56 -128
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/lookup.d.ts +16 -7
- package/dist/lookup.d.ts.map +1 -1
- package/dist/lookup.js +49 -7
- package/dist/query-compiler.d.ts.map +1 -1
- package/dist/query-compiler.js +141 -23
- package/dist/rebuild-support.d.ts +1 -41
- package/dist/rebuild-support.d.ts.map +1 -1
- package/dist/rebuild-support.js +3 -76
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +62 -10
- package/package.json +4 -4
- package/dist/import.d.ts +0 -31
- package/dist/import.d.ts.map +0 -1
- package/dist/import.js +0 -60
- package/dist/sweep.d.ts +0 -70
- package/dist/sweep.d.ts.map +0 -1
- package/dist/sweep.js +0 -113
package/dist/import.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/** Documents imported per Typesense request unless a writer is told otherwise. */
|
|
2
|
-
export const DEFAULT_BATCH_SIZE = 1000;
|
|
3
|
-
/**
|
|
4
|
-
* Accumulates documents across writes and upserts them into a collection in
|
|
5
|
-
* fixed-size batches, so many small writes (one dataset at a time) still land
|
|
6
|
-
* as few Typesense requests. Call {@link flush} to import the remainder.
|
|
7
|
-
*/
|
|
8
|
-
export class BatchImporter {
|
|
9
|
-
client;
|
|
10
|
-
collection;
|
|
11
|
-
batchSize;
|
|
12
|
-
buffer = [];
|
|
13
|
-
constructor(client, collection, batchSize) {
|
|
14
|
-
this.client = client;
|
|
15
|
-
this.collection = collection;
|
|
16
|
-
this.batchSize = batchSize;
|
|
17
|
-
}
|
|
18
|
-
/** Add a stream of documents, importing a batch whenever one fills up. */
|
|
19
|
-
async add(documents) {
|
|
20
|
-
for await (const document of documents) {
|
|
21
|
-
this.buffer.push(document);
|
|
22
|
-
if (this.buffer.length >= this.batchSize) {
|
|
23
|
-
await this.importBuffer();
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
/** Import any remaining documents. */
|
|
28
|
-
async flush() {
|
|
29
|
-
if (this.buffer.length > 0) {
|
|
30
|
-
await this.importBuffer();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
async importBuffer() {
|
|
34
|
-
const batch = this.buffer;
|
|
35
|
-
this.buffer = [];
|
|
36
|
-
await importBatch(this.client, this.collection, batch);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Create-or-replace one batch of whole documents, keyed on `id`, throwing if any
|
|
41
|
-
* individual document fails (Typesense’s bulk import otherwise reports
|
|
42
|
-
* per-document failures without rejecting).
|
|
43
|
-
*/
|
|
44
|
-
export async function importBatch(client, collection, batch) {
|
|
45
|
-
const results = (await client
|
|
46
|
-
.collections(collection)
|
|
47
|
-
.documents()
|
|
48
|
-
.import(batch, {
|
|
49
|
-
action: 'upsert',
|
|
50
|
-
// Collect per-document outcomes instead of throwing the client’s opaque
|
|
51
|
-
// ImportError, so we can report which documents failed and why.
|
|
52
|
-
throwOnFail: false,
|
|
53
|
-
}));
|
|
54
|
-
const failures = results.filter((result) => !result.success);
|
|
55
|
-
if (failures.length > 0) {
|
|
56
|
-
throw new Error(`Typesense upsert into “${collection}” failed for ${failures.length}/${results.length} documents: ${failures
|
|
57
|
-
.map((failure) => failure.error)
|
|
58
|
-
.join('; ')}`);
|
|
59
|
-
}
|
|
60
|
-
}
|
package/dist/sweep.d.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { SearchType } from '@lde/search';
|
|
2
|
-
/** The private field carrying the dataset IRI a document came from, for a type
|
|
3
|
-
* that declares none of its own – see {@link provenanceField}. */
|
|
4
|
-
export declare const SOURCE_FIELD = "source";
|
|
5
|
-
/** The document field carrying the id of the run that last wrote a document. */
|
|
6
|
-
export declare const LAST_SEEN_FIELD = "last_seen";
|
|
7
|
-
/**
|
|
8
|
-
* The field a collection carries its documents’ dataset IRI in – the one the
|
|
9
|
-
* membership sweep enumerates, filters and deletes by.
|
|
10
|
-
*
|
|
11
|
-
* A type that declares a field over the dataset
|
|
12
|
-
* ({@link datasetField `from: 'dataset'`}) *is* its provenance: the writer keeps
|
|
13
|
-
* its bookkeeping on that field rather than stamping a private one beside it,
|
|
14
|
-
* so the facet, the label resolution, any `derive` and the sweep all read one
|
|
15
|
-
* column that cannot drift. A type declaring nothing – or declaring the dataset
|
|
16
|
-
* only as an *internal* field, which the projection prunes before the writer
|
|
17
|
-
* ever sees it – falls back to the private {@link SOURCE_FIELD}, and behaves
|
|
18
|
-
* exactly as it always has.
|
|
19
|
-
*/
|
|
20
|
-
export declare function provenanceField(searchType: SearchType): string;
|
|
21
|
-
/**
|
|
22
|
-
* Sources whose documents must leave the index: indexed, but no longer part
|
|
23
|
-
* of the run’s selection. Selection is membership, not processing – a dataset
|
|
24
|
-
* skipped as unchanged is still selected, so its documents survive.
|
|
25
|
-
*
|
|
26
|
-
* @param indexedSources Source IRIs present in the collection
|
|
27
|
-
* @param selectedSources Source IRIs the run’s selector produced
|
|
28
|
-
*/
|
|
29
|
-
export declare function departedSources(indexedSources: Iterable<string>, selectedSources: Iterable<string>): string[];
|
|
30
|
-
/**
|
|
31
|
-
* Typesense filter matching a source’s documents that this run did not touch:
|
|
32
|
-
* everything the source no longer contains, ready for a per-source sweep.
|
|
33
|
-
*
|
|
34
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
35
|
-
* @param sourceIri The dataset IRI the documents carry in that field
|
|
36
|
-
* @param runId The current run; documents it wrote carry it as `last_seen`
|
|
37
|
-
*/
|
|
38
|
-
export declare function staleDocumentsFilter(sourceField: string, sourceIri: string, runId: string): string;
|
|
39
|
-
/**
|
|
40
|
-
* Typesense filter matching all of a source’s documents, ready to drop a whole
|
|
41
|
-
* source (a departed source’s membership sweep, or a Blue/green writer rolling
|
|
42
|
-
* a failed dataset out of its not-yet-live collection).
|
|
43
|
-
*
|
|
44
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
45
|
-
* @param sourceIri The dataset IRI the documents carry in that field
|
|
46
|
-
*/
|
|
47
|
-
export declare function sourceDocumentsFilter(sourceField: string, sourceIri: string): string;
|
|
48
|
-
/**
|
|
49
|
-
* Typesense filter matching the documents **this run** wrote for a source: the
|
|
50
|
-
* inverse of {@link staleDocumentsFilter}. An In-place writer deletes these to
|
|
51
|
-
* discard a source’s in-progress writes (the dump-fallback reset) without
|
|
52
|
-
* touching its prior-run documents, which the success sweep or a failed run
|
|
53
|
-
* still owns.
|
|
54
|
-
*
|
|
55
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
56
|
-
* @param sourceIri The dataset IRI the documents carry in that field
|
|
57
|
-
* @param runId The current run, stamped on its documents as `last_seen`
|
|
58
|
-
*/
|
|
59
|
-
export declare function thisRunDocumentsFilter(sourceField: string, sourceIri: string, runId: string): string;
|
|
60
|
-
/**
|
|
61
|
-
* Typesense filters deleting every departed source’s documents, combined into
|
|
62
|
-
* as few filters as fit: deletes travel in the URL query string, so each
|
|
63
|
-
* filter stays under a conservative length budget rather than listing every
|
|
64
|
-
* source in one string.
|
|
65
|
-
*
|
|
66
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
67
|
-
* @param departed The departed source IRIs ({@link departedSources})
|
|
68
|
-
*/
|
|
69
|
-
export declare function membershipSweepFilters(sourceField: string, departed: readonly string[]): string[];
|
|
70
|
-
//# sourceMappingURL=sweep.d.ts.map
|
package/dist/sweep.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sweep.d.ts","sourceRoot":"","sources":["../src/sweep.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C;mEACmE;AACnE,eAAO,MAAM,YAAY,WAAW,CAAC;AAErC,gFAAgF;AAChF,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAK9D;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,EAChC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,GAChC,MAAM,EAAE,CAGV;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAER;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,MAAM,EAAE,CAqBV"}
|
package/dist/sweep.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
// Pure deletion planning shared by the rebuild writers: which documents leave
|
|
2
|
-
// a collection, expressed as source sets and Typesense filter strings. Kept
|
|
3
|
-
// free of the Typesense client so the logic is unit-testable. This module owns
|
|
4
|
-
// the private bookkeeping field names and resolves which field a collection
|
|
5
|
-
// carries its provenance in, so stamping and every filter that reads it can
|
|
6
|
-
// never disagree.
|
|
7
|
-
import { datasetField, isInternalField } from '@lde/search/adapter';
|
|
8
|
-
import { escapeFilterValue } from './query-compiler.js';
|
|
9
|
-
/** The private field carrying the dataset IRI a document came from, for a type
|
|
10
|
-
* that declares none of its own – see {@link provenanceField}. */
|
|
11
|
-
export const SOURCE_FIELD = 'source';
|
|
12
|
-
/** The document field carrying the id of the run that last wrote a document. */
|
|
13
|
-
export const LAST_SEEN_FIELD = 'last_seen';
|
|
14
|
-
/**
|
|
15
|
-
* The field a collection carries its documents’ dataset IRI in – the one the
|
|
16
|
-
* membership sweep enumerates, filters and deletes by.
|
|
17
|
-
*
|
|
18
|
-
* A type that declares a field over the dataset
|
|
19
|
-
* ({@link datasetField `from: 'dataset'`}) *is* its provenance: the writer keeps
|
|
20
|
-
* its bookkeeping on that field rather than stamping a private one beside it,
|
|
21
|
-
* so the facet, the label resolution, any `derive` and the sweep all read one
|
|
22
|
-
* column that cannot drift. A type declaring nothing – or declaring the dataset
|
|
23
|
-
* only as an *internal* field, which the projection prunes before the writer
|
|
24
|
-
* ever sees it – falls back to the private {@link SOURCE_FIELD}, and behaves
|
|
25
|
-
* exactly as it always has.
|
|
26
|
-
*/
|
|
27
|
-
export function provenanceField(searchType) {
|
|
28
|
-
const declared = datasetField(searchType);
|
|
29
|
-
return declared === undefined || isInternalField(declared)
|
|
30
|
-
? SOURCE_FIELD
|
|
31
|
-
: declared.name;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Sources whose documents must leave the index: indexed, but no longer part
|
|
35
|
-
* of the run’s selection. Selection is membership, not processing – a dataset
|
|
36
|
-
* skipped as unchanged is still selected, so its documents survive.
|
|
37
|
-
*
|
|
38
|
-
* @param indexedSources Source IRIs present in the collection
|
|
39
|
-
* @param selectedSources Source IRIs the run’s selector produced
|
|
40
|
-
*/
|
|
41
|
-
export function departedSources(indexedSources, selectedSources) {
|
|
42
|
-
const selected = new Set(selectedSources);
|
|
43
|
-
return [...indexedSources].filter((source) => !selected.has(source));
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Typesense filter matching a source’s documents that this run did not touch:
|
|
47
|
-
* everything the source no longer contains, ready for a per-source sweep.
|
|
48
|
-
*
|
|
49
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
50
|
-
* @param sourceIri The dataset IRI the documents carry in that field
|
|
51
|
-
* @param runId The current run; documents it wrote carry it as `last_seen`
|
|
52
|
-
*/
|
|
53
|
-
export function staleDocumentsFilter(sourceField, sourceIri, runId) {
|
|
54
|
-
return `${sourceDocumentsFilter(sourceField, sourceIri)} && ${LAST_SEEN_FIELD}:!=${escapeFilterValue(runId)}`;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Typesense filter matching all of a source’s documents, ready to drop a whole
|
|
58
|
-
* source (a departed source’s membership sweep, or a Blue/green writer rolling
|
|
59
|
-
* a failed dataset out of its not-yet-live collection).
|
|
60
|
-
*
|
|
61
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
62
|
-
* @param sourceIri The dataset IRI the documents carry in that field
|
|
63
|
-
*/
|
|
64
|
-
export function sourceDocumentsFilter(sourceField, sourceIri) {
|
|
65
|
-
return `${sourceField}:=${escapeFilterValue(sourceIri)}`;
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Typesense filter matching the documents **this run** wrote for a source: the
|
|
69
|
-
* inverse of {@link staleDocumentsFilter}. An In-place writer deletes these to
|
|
70
|
-
* discard a source’s in-progress writes (the dump-fallback reset) without
|
|
71
|
-
* touching its prior-run documents, which the success sweep or a failed run
|
|
72
|
-
* still owns.
|
|
73
|
-
*
|
|
74
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
75
|
-
* @param sourceIri The dataset IRI the documents carry in that field
|
|
76
|
-
* @param runId The current run, stamped on its documents as `last_seen`
|
|
77
|
-
*/
|
|
78
|
-
export function thisRunDocumentsFilter(sourceField, sourceIri, runId) {
|
|
79
|
-
return `${sourceDocumentsFilter(sourceField, sourceIri)} && ${LAST_SEEN_FIELD}:=${escapeFilterValue(runId)}`;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Typesense filters deleting every departed source’s documents, combined into
|
|
83
|
-
* as few filters as fit: deletes travel in the URL query string, so each
|
|
84
|
-
* filter stays under a conservative length budget rather than listing every
|
|
85
|
-
* source in one string.
|
|
86
|
-
*
|
|
87
|
-
* @param sourceField The collection’s {@link provenanceField}
|
|
88
|
-
* @param departed The departed source IRIs ({@link departedSources})
|
|
89
|
-
*/
|
|
90
|
-
export function membershipSweepFilters(sourceField, departed) {
|
|
91
|
-
const filters = [];
|
|
92
|
-
let chunk = [];
|
|
93
|
-
let chunkLength = 0;
|
|
94
|
-
const flush = () => {
|
|
95
|
-
if (chunk.length > 0) {
|
|
96
|
-
filters.push(`${sourceField}:=[${chunk.join(',')}]`);
|
|
97
|
-
chunk = [];
|
|
98
|
-
chunkLength = 0;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
for (const source of departed) {
|
|
102
|
-
const escaped = escapeFilterValue(source);
|
|
103
|
-
if (chunkLength + escaped.length > MAX_FILTER_VALUES_LENGTH) {
|
|
104
|
-
flush();
|
|
105
|
-
}
|
|
106
|
-
chunk.push(escaped);
|
|
107
|
-
chunkLength += escaped.length + 1;
|
|
108
|
-
}
|
|
109
|
-
flush();
|
|
110
|
-
return filters;
|
|
111
|
-
}
|
|
112
|
-
/** Stay well under Typesense’s ~4000-char URL query-string limit per delete. */
|
|
113
|
-
const MAX_FILTER_VALUES_LENGTH = 3000;
|