mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-27 01:13:27 +03:00
Elastic priority by matching space & class (#730)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
0049dad2d8
commit
816823f9af
@ -117,16 +117,15 @@ export class FullTextIndex implements WithFind {
|
||||
console.log('search', query)
|
||||
const { _id, $search, ...mainQuery } = query
|
||||
if ($search === undefined) return []
|
||||
const docs = await this.adapter.search($search)
|
||||
const docs = await this.adapter.search(_class, query, options?.limit)
|
||||
console.log(docs)
|
||||
const ids: Ref<Doc>[] = []
|
||||
const ids: Set<Ref<Doc>> = new Set<Ref<Doc>>(docs.map(p => p.id))
|
||||
for (const doc of docs) {
|
||||
ids.push(doc.id)
|
||||
if (doc.attachedTo !== undefined) {
|
||||
ids.push(doc.attachedTo)
|
||||
ids.add(doc.attachedTo)
|
||||
}
|
||||
}
|
||||
return await this.dbStorage.findAll(ctx, _class, { _id: { $in: ids as any }, ...mainQuery }, options) // TODO: remove `as any`
|
||||
return await this.dbStorage.findAll(ctx, _class, { _id: { $in: Array.from(ids) as any }, ...mainQuery }, options) // TODO: remove `as any`
|
||||
}
|
||||
|
||||
private getFullTextAttributes (clazz: Ref<Class<Obj>>): AnyAttribute[] | undefined {
|
||||
@ -203,6 +202,10 @@ export class FullTextIndex implements WithFind {
|
||||
}
|
||||
i++
|
||||
}
|
||||
if (tx.operations.space !== undefined) {
|
||||
update.space = tx.operations.space
|
||||
shouldUpdate = true
|
||||
}
|
||||
if (shouldUpdate) {
|
||||
result = await this.adapter.update(tx.objectId, update)
|
||||
await this.updateAttachedDocs(ctx, tx, update)
|
||||
@ -229,7 +232,9 @@ export class FullTextIndex implements WithFind {
|
||||
const docUpdate: any = {}
|
||||
for (const key in update) {
|
||||
const index = Number.parseInt(key.replace('content', ''))
|
||||
docUpdate[`content${index + shift}`] = update[key]
|
||||
if (!isNaN(index)) {
|
||||
docUpdate[`content${index + shift}`] = update[key]
|
||||
}
|
||||
}
|
||||
for (const attached of allAttached) {
|
||||
await this.adapter.update(attached._id, docUpdate)
|
||||
|
@ -64,7 +64,7 @@ export interface IndexedDoc {
|
||||
export interface FullTextAdapter {
|
||||
index: (doc: IndexedDoc) => Promise<TxResult>
|
||||
update: (id: Ref<Doc>, update: Record<string, any>) => Promise<TxResult>
|
||||
search: (search: string) => Promise<IndexedDoc[]>
|
||||
search: (_class: Ref<Class<Doc>>, search: DocumentQuery<Doc>, size: number | undefined) => Promise<IndexedDoc[]>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Ref, Doc, Class, Obj, Account, Space } from '@anticrm/core'
|
||||
import type { Ref, Doc, Class, Account, Space } from '@anticrm/core'
|
||||
import { createElasticAdapter } from '../adapter'
|
||||
import type { IndexedDoc } from '@anticrm/server-core'
|
||||
|
||||
@ -23,14 +23,14 @@ describe('client', () => {
|
||||
const adapter = await createElasticAdapter('http://localhost:9200/', 'ws1')
|
||||
const doc: IndexedDoc = {
|
||||
id: 'doc1' as Ref<Doc>,
|
||||
_class: 'class1' as Ref<Class<Obj>>,
|
||||
_class: 'class1' as Ref<Class<Doc>>,
|
||||
modifiedBy: 'andrey' as Ref<Account>,
|
||||
modifiedOn: 0,
|
||||
space: 'space1' as Ref<Space>,
|
||||
content0: 'hey there!'
|
||||
}
|
||||
await adapter.index(doc)
|
||||
const hits = await adapter.search('')
|
||||
const hits = await adapter.search('class1' as Ref<Class<Doc>>, {}, 1)
|
||||
console.log(hits)
|
||||
})
|
||||
|
||||
|
@ -14,33 +14,28 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import type { Doc, Ref, TxResult } from '@anticrm/core'
|
||||
import type { Class, Doc, DocumentQuery, Ref, TxResult } from '@anticrm/core'
|
||||
import type { FullTextAdapter, IndexedDoc } from '@anticrm/server-core'
|
||||
|
||||
import { Client } from '@elastic/elasticsearch'
|
||||
|
||||
class ElasticAdapter implements FullTextAdapter {
|
||||
constructor (
|
||||
private readonly client: Client,
|
||||
private readonly db: string
|
||||
) {
|
||||
}
|
||||
constructor (private readonly client: Client, private readonly db: string) {}
|
||||
|
||||
async close (): Promise<void> {
|
||||
await this.client.close()
|
||||
}
|
||||
|
||||
async search (
|
||||
search: string
|
||||
): Promise<IndexedDoc[]> {
|
||||
const query = search.replace(/[\\/+\-=&><!()|{}^"~*&:[\]]/g, '\\$&')
|
||||
try {
|
||||
const result = await this.client.search({
|
||||
index: this.db,
|
||||
body: {
|
||||
query: {
|
||||
async search (_class: Ref<Class<Doc>>, query: DocumentQuery<Doc>, size: number | undefined): Promise<IndexedDoc[]> {
|
||||
if (query.$search === undefined) return []
|
||||
const search = query.$search.replace(/[\\/+\-=&><!()|{}^"~*&:[\]]/g, '\\$&')
|
||||
|
||||
const request: any = {
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
multi_match: {
|
||||
query: query,
|
||||
query: search,
|
||||
fields: [
|
||||
'content0',
|
||||
'content1',
|
||||
@ -55,12 +50,43 @@ class ElasticAdapter implements FullTextAdapter {
|
||||
'attachment.content'
|
||||
]
|
||||
}
|
||||
},
|
||||
size: 200
|
||||
}
|
||||
],
|
||||
should: [
|
||||
{
|
||||
term: {
|
||||
_class: {
|
||||
value: _class,
|
||||
case_insensitive: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (query.space != null) {
|
||||
request.bool.should.push({
|
||||
term: {
|
||||
space: {
|
||||
value: query.space,
|
||||
boost: 2.0,
|
||||
case_insensitive: true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.client.search({
|
||||
index: this.db,
|
||||
body: {
|
||||
query: request,
|
||||
size: size ?? 200
|
||||
}
|
||||
})
|
||||
const hits = result.body.hits.hits as any[]
|
||||
return hits.map(hit => hit._source)
|
||||
return hits.map((hit) => hit._source)
|
||||
} catch (err) {
|
||||
console.error(JSON.stringify(err, null, 2))
|
||||
return []
|
||||
@ -115,7 +141,10 @@ class ElasticAdapter implements FullTextAdapter {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export async function createElasticAdapter (url: string, dbName: string): Promise<FullTextAdapter & {close: () => Promise<void>}> {
|
||||
export async function createElasticAdapter (
|
||||
url: string,
|
||||
dbName: string
|
||||
): Promise<FullTextAdapter & { close: () => Promise<void> }> {
|
||||
const client = new Client({
|
||||
node: url
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user