diff --git a/server/core/src/fulltext.ts b/server/core/src/fulltext.ts index 404d99e660..7b13bec4e9 100644 --- a/server/core/src/fulltext.ts +++ b/server/core/src/fulltext.ts @@ -145,28 +145,33 @@ export class FullTextIndex implements WithFind { if ($search === undefined) return toFindResult([]) let skip = 0 - const result: FindResult = toFindResult([]) + const ids: Set> = new Set>() + const baseClass = this.hierarchy.getBaseClass(_class) + const classes = this.hierarchy.getDescendants(baseClass) + const fullTextLimit = 10000 while (true) { - const docs = await this.adapter.search(_class, query, options?.limit, skip) - if (docs.length === 0) { - result.total = result.length - return result - } - skip += docs.length - const ids: Set> = new Set>(docs.map((p) => p.id)) + const docs = await this.adapter.search(classes, query, fullTextLimit, skip) for (const doc of docs) { + ids.add(doc.id) if (doc.attachedTo !== undefined) { ids.add(doc.attachedTo) } } - const resultIds = getResultIds(ids, _id) - const current = await this.dbStorage.findAll(ctx, _class, { _id: { $in: resultIds }, ...mainQuery }, options) - result.push(...current) - result.total += current.total - if (result.length > 0 && result.length >= (options?.limit ?? 0)) { - return result + if (docs.length < fullTextLimit) { + break } + skip += docs.length } + const resultIds = getResultIds(ids, _id) + const { limit, ...otherOptions } = options ?? { } + const result = await this.dbStorage.findAll(ctx, _class, { _id: { $in: resultIds }, ...mainQuery }, otherOptions) + const total = result.total + result.sort((a, b) => resultIds.indexOf(a._id) - resultIds.indexOf(b._id)) + if (limit !== undefined) { + const res = toFindResult(result.splice(0, limit), total) + return res + } + return toFindResult(result, total) } private getFullTextAttributes (clazz: Ref>, parentDoc?: Doc): AnyAttribute[] { diff --git a/server/core/src/types.ts b/server/core/src/types.ts index 3a460b82b4..12b8368bfc 100644 --- a/server/core/src/types.ts +++ b/server/core/src/types.ts @@ -68,7 +68,7 @@ export interface FullTextAdapter { index: (doc: IndexedDoc) => Promise update: (id: Ref, update: Record) => Promise remove: (id: Ref) => Promise - search: (_class: Ref>, search: DocumentQuery, size: number | undefined, from?: number) => Promise + search: (_classes: Ref>[], search: DocumentQuery, size: number | undefined, from?: number) => Promise close: () => Promise } diff --git a/server/elastic/src/__tests__/adapter.test.ts b/server/elastic/src/__tests__/adapter.test.ts index 03812b6204..9c028d0907 100644 --- a/server/elastic/src/__tests__/adapter.test.ts +++ b/server/elastic/src/__tests__/adapter.test.ts @@ -30,7 +30,7 @@ describe('client', () => { content0: 'hey there!' } await adapter.index(doc) - const hits = await adapter.search('class1' as Ref>, {}, 1) + const hits = await adapter.search(['class1' as Ref>], {}, 1) console.log(hits) }) diff --git a/server/elastic/src/adapter.ts b/server/elastic/src/adapter.ts index 276c545245..ee184ff8ed 100644 --- a/server/elastic/src/adapter.ts +++ b/server/elastic/src/adapter.ts @@ -25,7 +25,7 @@ class ElasticAdapter implements FullTextAdapter { await this.client.close() } - async search (_class: Ref>, query: DocumentQuery, size: number | undefined, from: number | undefined): Promise { + async search (_classes: Ref>[], query: DocumentQuery, size: number | undefined, from: number | undefined): Promise { if (query.$search === undefined) return [] const request: any = { bool: { @@ -39,11 +39,9 @@ class ElasticAdapter implements FullTextAdapter { ], should: [ { - term: { - _class: { - value: _class, - case_insensitive: true - } + terms: { + _class: _classes.map((c) => c.toLowerCase()), + boost: 10.0 } } ] @@ -53,12 +51,9 @@ class ElasticAdapter implements FullTextAdapter { if (query.space != null) { if (typeof query.space === 'object' && query.space.$in !== undefined) { request.bool.should.push({ - term: { - space: { - value: query.space.$in, - boost: 2.0, - case_insensitive: true - } + terms: { + space: query.space.$in.map((c) => c.toLowerCase()), + boost: 2.0 } }) } else {