Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DAT-63] feat: Improve search performances #8

Merged
merged 1 commit into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/@types/cozy-client.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,14 @@ declare module 'cozy-client' {
queryDefinition: QueryDefinition,
options?: QueryOptions
) => Promise<QueryResult>
queryAll: <T>(queryDefinition: QueryDefinition) => Promise<T>
queryAll: <T>(
queryDefinition: QueryDefinition,
options?: QueryOptions
) => Promise<T>
links: CozyLink[]
capabilities: ClientCapabilities
registerPlugin: (Plugin: Function, options: unknown) => void
getCollectionFromState: (doctype: string) => unknown
}

export const createMockClient = (options?: ClientOptions): CozyClient =>
Expand Down
2 changes: 1 addition & 1 deletion src/dataproxy/common/DataProxyInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { ClientCapabilities } from 'cozy-client/types/types'
export type { SearchIndexes } from '@/search/types'

export interface DataProxyWorker {
search: (query: string) => Promise<unknown>
search: (query: string) => unknown
setClient: (clientData: ClientData) => Promise<void>
}

Expand Down
9 changes: 6 additions & 3 deletions src/dataproxy/worker/shared-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const dataProxy: DataProxyWorker = {
updateState()
},

search: async (query: string) => {
search: (query: string) => {
if (!client) {
throw new Error(
'Client is required to execute a search, please initialize CozyClient'
Expand All @@ -75,8 +75,11 @@ const dataProxy: DataProxyWorker = {
if (!searchEngine) {
throw new Error('SearchEngine is not initialized')
}

return searchEngine.search(query)
const startSearchTime = performance.now()
const results = searchEngine.search(query)
const endSearchTime = performance.now()
log.debug(`Search took ${endSearchTime - startSearchTime} ms`)
return results
}
}

Expand Down
13 changes: 7 additions & 6 deletions src/search/SearchEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
isSearchedDoctype
} from '@/search/types'

import { shouldKeepFile } from './helpers/normalizeFile'
import { addFilePaths, shouldKeepFile } from './helpers/normalizeFile'

const log = Minilog('🗂️ [Indexing]')

Expand Down Expand Up @@ -254,9 +254,7 @@ class SearchEngine {
return this.searchIndexes
}

async search(query: string): Promise<SearchResult[]> {
log.debug('[SEARCH] indexes : ', this.searchIndexes)

search(query: string): SearchResult[] {
if (!this.searchIndexes) {
// TODO: What if the indexing is running but not finished yet?
log.warn('[SEARCH] No search index available')
Expand All @@ -269,8 +267,9 @@ class SearchEngine {
const results = this.limitSearchResults(sortedResults)

const normResults: SearchResult[] = []
for (const res of results) {
const normalizedRes = await normalizeSearchResult(this.client, res, query)
const completedResults = addFilePaths(this.client, results)
for (const res of completedResults) {
const normalizedRes = normalizeSearchResult(this.client, res, query)
normResults.push(normalizedRes)
}
return normResults.filter(res => res.title)
Expand Down Expand Up @@ -301,12 +300,14 @@ class SearchEngine {
limit: FLEXSEARCH_LIMIT,
enrich: true
})

const newResults = indexResults.map(res => ({
...res,
doctype: doctype
}))
searchResults = searchResults.concat(newResults)
}

return searchResults
}

Expand Down
1 change: 1 addition & 0 deletions src/search/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const CONTACTS_DOCTYPE = 'io.cozy.contacts'
export const APPS_DOCTYPE = 'io.cozy.apps'

export const TYPE_DIRECTORY = 'directory'
export const TYPE_FILE = 'file'
export const ROOT_DIR_ID = 'io.cozy.files.root-dir'
export const TRASH_DIR_ID = 'io.cozy.files.trash-dir'
export const SHARED_DRIVES_DIR_ID = 'io.cozy.files.shared-drives-dir'
Expand Down
57 changes: 34 additions & 23 deletions src/search/helpers/normalizeFile.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import CozyClient, { Q } from 'cozy-client'
import CozyClient from 'cozy-client'
import { IOCozyFile } from 'cozy-client/types/types'

import {
FILES_DOCTYPE,
TYPE_DIRECTORY,
TYPE_FILE,
ROOT_DIR_ID,
SHARED_DRIVES_DIR_ID
} from '@/search/consts'
import { CozyDoc } from '@/search/types'

interface FileQueryResult {
data: IOCozyFile
}
import { CozyDoc, isIOCozyFile, RawSearchResult } from '@/search/types'

/**
* Normalize file for Front usage in <AutoSuggestion> component inside <BarSearchAutosuggest>
Expand Down Expand Up @@ -39,25 +36,39 @@ export const normalizeFileWithFolders = (
return { ...file, _type: 'io.cozy.files', path }
}

export const normalizeFileWithStore = async (
export const addFilePaths = (
client: CozyClient,
file: IOCozyFile
): Promise<IOCozyFile> => {
const isDir = file.type === TYPE_DIRECTORY
let path = ''
if (isDir) {
path = file.path ?? ''
} else {
const query = Q(FILES_DOCTYPE).getById(file.dir_id).limitBy(1)
// XXX - Take advantage of cozy-client store to avoid querying database
const { data: parentDir } = (await client.query(query, {
executeFromStore: true,
singleDocData: true
})) as FileQueryResult
const parentPath = parentDir?.path ?? ''
path = `${parentPath}/${file.name}`
results: RawSearchResult[]
): RawSearchResult[] => {
const normResults = [...results]
const filesResults = normResults
.map(res => res.doc)
.filter(doc => isIOCozyFile(doc))
const files = filesResults.filter(file => file.type === TYPE_FILE)

if (files.length > 0) {
const dirIds = files.map(file => file.dir_id)
const parentDirs = getDirsFromStore(client, dirIds)
for (const file of files) {
const dir = parentDirs.find(dir => dir._id === file.dir_id)
if (dir) {
const idx = normResults.findIndex(res => res.doc._id === file._id)
normResults[idx].doc.path = dir.path
}
}
}
return { ...file, _type: 'io.cozy.files', path }
return normResults
}

const getDirsFromStore = (
client: CozyClient,
dirIds: string[]
): IOCozyFile[] => {
// XXX querying from store is surprisingly slow: 100+ ms for 50 docs, while
// this approach takes 2-3ms... It should be investigated in cozy-client
const allFiles = client.getCollectionFromState(FILES_DOCTYPE) as IOCozyFile[]
const dirs = allFiles.filter(file => file.type === TYPE_DIRECTORY)
return dirs.filter(dir => dirIds.includes(dir._id))
}

export const shouldKeepFile = (file: IOCozyFile): boolean => {
Expand Down
18 changes: 3 additions & 15 deletions src/search/helpers/normalizeSearchResult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,12 @@ import {
SearchResult
} from '@/search/types'

import { normalizeFileWithStore } from './normalizeFile'

export const normalizeSearchResult = async (
export const normalizeSearchResult = (
client: CozyClient,
searchResults: RawSearchResult,
query: string
): Promise<SearchResult> => {
const doc = await normalizeDoc(client, searchResults.doc)
): SearchResult => {
const doc = searchResults.doc
const url = buildOpenURL(client, doc)
const type = getSearchResultSlug(doc)
const title = getSearchResultTitle(doc)
Expand All @@ -32,16 +30,6 @@ export const normalizeSearchResult = async (
return normalizedRes
}

const normalizeDoc = async (
client: CozyClient,
doc: CozyDoc
): Promise<CozyDoc> => {
if (isIOCozyFile(doc)) {
return normalizeFileWithStore(client, doc)
}
return doc
}

const getSearchResultTitle = (doc: CozyDoc): string | null => {
if (isIOCozyFile(doc)) {
return doc.name
Expand Down