feat(native): native reader for indexer (#14055)

This commit is contained in:
DarkSky
2025-12-07 16:22:11 +08:00
committed by GitHub
parent 69cdeedc4e
commit cf4e37c584
28 changed files with 1376 additions and 569 deletions
@@ -117,6 +117,8 @@ export class IndexerSyncImpl implements IndexerSync {
private readonly indexer: IndexerStorage;
private readonly remote?: IndexerStorage;
private lastRefreshed = Date.now();
state$ = this.status.state$.pipe(
// throttle the state to 1 second to avoid spamming the UI
throttleTime(1000, undefined, {
@@ -378,8 +380,7 @@ export class IndexerSyncImpl implements IndexerSync {
this.status.statusUpdatedSubject$.next(docId);
}
}
await this.indexer.refresh('block');
await this.indexer.refresh('doc');
await this.refreshIfNeed();
// #endregion
} else {
// #region crawl doc
@@ -407,33 +408,40 @@ export class IndexerSyncImpl implements IndexerSync {
continue;
}
const docBin = await this.doc.getDoc(docId);
if (!docBin) {
// doc is deleted, just skip
continue;
}
console.log('[indexer] start indexing doc', docId);
const docYDoc = new YDoc({ guid: docId });
applyUpdate(docYDoc, docBin.bin);
let blocks: IndexerDocument<'block'>[] = [];
let preview: string | undefined;
try {
const result = await crawlingDocData({
ydoc: docYDoc,
rootYDoc: this.status.rootDoc,
spaceId: this.status.rootDocId,
docId,
});
if (!result) {
// doc is empty without root block, just skip
const nativeResult = await this.tryNativeCrawlDocData(docId);
if (nativeResult) {
blocks = nativeResult.block;
preview = nativeResult.summary;
} else {
const docBin = await this.doc.getDoc(docId);
if (!docBin) {
// doc is deleted, just skip
continue;
}
blocks = result.blocks;
preview = result.preview;
} catch (error) {
console.error('error crawling doc', error);
const docYDoc = new YDoc({ guid: docId });
applyUpdate(docYDoc, docBin.bin);
try {
const result = await crawlingDocData({
ydoc: docYDoc,
rootYDoc: this.status.rootDoc,
spaceId: this.status.rootDocId,
docId,
});
if (!result) {
// doc is empty without root block, just skip
continue;
}
blocks = result.blocks;
preview = result.preview;
} catch (error) {
console.error('error crawling doc', error);
}
}
await this.indexer.deleteByQuery('block', {
@@ -446,8 +454,6 @@ export class IndexerSyncImpl implements IndexerSync {
await this.indexer.insert('block', block);
}
await this.indexer.refresh('block');
if (preview) {
await this.indexer.update(
'doc',
@@ -455,9 +461,10 @@ export class IndexerSyncImpl implements IndexerSync {
summary: preview,
})
);
await this.indexer.refresh('doc');
}
await this.refreshIfNeed();
await this.indexerSync.setDocIndexedClock({
docId,
timestamp: docClock.timestamp,
@@ -471,10 +478,19 @@ export class IndexerSyncImpl implements IndexerSync {
this.status.completeJob();
}
} finally {
await this.refreshIfNeed();
unsubscribe();
}
}
private async refreshIfNeed(): Promise<void> {
if (this.lastRefreshed + 100 < Date.now()) {
console.log('[indexer] refreshing indexer');
await this.indexer.refreshIfNeed();
this.lastRefreshed = Date.now();
}
}
/**
* Get all docs from the root doc, without deleted docs
*/
@@ -484,6 +500,36 @@ export class IndexerSyncImpl implements IndexerSync {
});
}
private async tryNativeCrawlDocData(docId: string) {
try {
const result = await this.doc.crawlDocData?.(docId);
if (result) {
return {
title: result.title,
block: result.blocks.map(block =>
IndexerDocument.from<'block'>(`${docId}:${block.blockId}`, {
docId,
blockId: block.blockId,
content: block.content,
flavour: block.flavour,
blob: block.blob,
refDocId: block.refDocId,
ref: block.refInfo,
parentFlavour: block.parentFlavour,
parentBlockId: block.parentBlockId,
additional: block.additional,
})
),
summary: result.summary,
};
}
return null;
} catch (error) {
console.warn('[indexer] native crawlDocData failed', docId, error);
return null;
}
}
private async getAllDocsFromIndexer() {
const docs = await this.indexer.search(
'doc',