Feature/172 recency (#439)
* Fixed ts errors * #172 - First draft at recency boost
This commit is contained in:
@@ -98,9 +98,9 @@
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let elFolderPathIcon: HTMLElement
|
let elFolderPathIcon: HTMLElement | null = null
|
||||||
let elFilePathIcon: HTMLElement
|
let elFilePathIcon: HTMLElement | null = null
|
||||||
let elEmbedIcon: HTMLElement
|
let elEmbedIcon: HTMLElement | null = null
|
||||||
|
|
||||||
$: {
|
$: {
|
||||||
imagePath = null
|
imagePath = null
|
||||||
|
|||||||
@@ -41,6 +41,13 @@ export const enum Action {
|
|||||||
OpenInNewLeaf = 'open-in-new-leaf',
|
OpenInNewLeaf = 'open-in-new-leaf',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum RecencyCutoff {
|
||||||
|
Disabled = '0',
|
||||||
|
Day = '1',
|
||||||
|
Week = '2',
|
||||||
|
Month = '3',
|
||||||
|
}
|
||||||
|
|
||||||
export type DocumentRef = { path: string; mtime: number }
|
export type DocumentRef = { path: string; mtime: number }
|
||||||
|
|
||||||
export type IndexedDocument = {
|
export type IndexedDocument = {
|
||||||
@@ -100,8 +107,8 @@ export type TextExtractorApi = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type AIImageAnalyzerAPI = {
|
export type AIImageAnalyzerAPI = {
|
||||||
analyzeImage: (file: TFile) => Promise<string>;
|
analyzeImage: (file: TFile) => Promise<string>
|
||||||
canBeAnalyzed: (file: TFile) => boolean;
|
canBeAnalyzed: (file: TFile) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SEPARATORS =
|
export const SEPARATORS =
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ import MiniSearch, {
|
|||||||
type Options,
|
type Options,
|
||||||
type SearchResult,
|
type SearchResult,
|
||||||
} from 'minisearch'
|
} from 'minisearch'
|
||||||
import type { DocumentRef, IndexedDocument, ResultNote } from '../globals'
|
import {
|
||||||
|
RecencyCutoff,
|
||||||
|
type DocumentRef,
|
||||||
|
type IndexedDocument,
|
||||||
|
type ResultNote,
|
||||||
|
} from '../globals'
|
||||||
|
|
||||||
import { chunkArray, logVerbose, removeDiacritics } from '../tools/utils'
|
import { chunkArray, logVerbose, removeDiacritics } from '../tools/utils'
|
||||||
import { Notice } from 'obsidian'
|
import { Notice } from 'obsidian'
|
||||||
@@ -60,7 +65,7 @@ export class SearchEngine {
|
|||||||
!this.indexedDocuments.has(d.path) ||
|
!this.indexedDocuments.has(d.path) ||
|
||||||
this.indexedDocuments.get(d.path) !== d.mtime
|
this.indexedDocuments.get(d.path) !== d.mtime
|
||||||
)
|
)
|
||||||
|
|
||||||
const toRemove = [...this.indexedDocuments]
|
const toRemove = [...this.indexedDocuments]
|
||||||
.filter(
|
.filter(
|
||||||
([path, mtime]) => !docsMap.has(path) || docsMap.get(path) !== mtime
|
([path, mtime]) => !docsMap.has(path) || docsMap.get(path) !== mtime
|
||||||
@@ -171,6 +176,25 @@ export class SearchEngine {
|
|||||||
},
|
},
|
||||||
// The query is already tokenized, don't tokenize again
|
// The query is already tokenized, don't tokenize again
|
||||||
tokenize: text => [text],
|
tokenize: text => [text],
|
||||||
|
boostDocument(_id, _term, storedFields) {
|
||||||
|
if (
|
||||||
|
!storedFields?.mtime ||
|
||||||
|
settings.recencyBoost === RecencyCutoff.Disabled
|
||||||
|
) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
const mtime = storedFields?.mtime as number
|
||||||
|
const now = new Date().valueOf()
|
||||||
|
const daysElapsed = (now - mtime) / (24 * 3600)
|
||||||
|
|
||||||
|
// Documents boost
|
||||||
|
const cutoff = {
|
||||||
|
[RecencyCutoff.Day]: -3,
|
||||||
|
[RecencyCutoff.Week]: -0.3,
|
||||||
|
[RecencyCutoff.Month]: -0.1,
|
||||||
|
} as const
|
||||||
|
return 1 + Math.exp(cutoff[settings.recencyBoost] * daysElapsed)
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
logVerbose(`Found ${results.length} results`, results)
|
logVerbose(`Found ${results.length} results`, results)
|
||||||
@@ -300,7 +324,8 @@ export class SearchEngine {
|
|||||||
|
|
||||||
const documents = await Promise.all(
|
const documents = await Promise.all(
|
||||||
results.map(
|
results.map(
|
||||||
async result => await this.plugin.documentsRepository.getDocument(result.id)
|
async result =>
|
||||||
|
await this.plugin.documentsRepository.getDocument(result.id)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -376,7 +401,8 @@ export class SearchEngine {
|
|||||||
|
|
||||||
const documents = await Promise.all(
|
const documents = await Promise.all(
|
||||||
results.map(
|
results.map(
|
||||||
async result => await this.plugin.documentsRepository.getDocument(result.id)
|
async result =>
|
||||||
|
await this.plugin.documentsRepository.getDocument(result.id)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -503,7 +529,7 @@ export class SearchEngine {
|
|||||||
'headings2',
|
'headings2',
|
||||||
'headings3',
|
'headings3',
|
||||||
],
|
],
|
||||||
storeFields: ['tags'],
|
storeFields: ['tags', 'mtime'],
|
||||||
logger(_level, _message, code) {
|
logger(_level, _message, code) {
|
||||||
if (code === 'version_conflict') {
|
if (code === 'version_conflict') {
|
||||||
new Notice(
|
new Notice(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
SliderComponent,
|
SliderComponent,
|
||||||
} from 'obsidian'
|
} from 'obsidian'
|
||||||
import { writable } from 'svelte/store'
|
import { writable } from 'svelte/store'
|
||||||
import { K_DISABLE_OMNISEARCH } from './globals'
|
import { K_DISABLE_OMNISEARCH, RecencyCutoff } from './globals'
|
||||||
import type OmnisearchPlugin from './main'
|
import type OmnisearchPlugin from './main'
|
||||||
import { enableVerboseLogging, getCtrlKeyLabel } from './tools/utils'
|
import { enableVerboseLogging, getCtrlKeyLabel } from './tools/utils'
|
||||||
import { debounce } from 'lodash-es'
|
import { debounce } from 'lodash-es'
|
||||||
@@ -29,6 +29,8 @@ export interface OmnisearchSettings extends WeightingSettings {
|
|||||||
useCache: boolean
|
useCache: boolean
|
||||||
/** Respect the "excluded files" Obsidian setting by downranking results ignored files */
|
/** Respect the "excluded files" Obsidian setting by downranking results ignored files */
|
||||||
hideExcluded: boolean
|
hideExcluded: boolean
|
||||||
|
/** Boost more recent files */
|
||||||
|
recencyBoost: RecencyCutoff
|
||||||
/** downrank files in the given folders */
|
/** downrank files in the given folders */
|
||||||
downrankedFoldersFilters: string[]
|
downrankedFoldersFilters: string[]
|
||||||
/** Ignore diacritics when indexing files */
|
/** Ignore diacritics when indexing files */
|
||||||
@@ -317,6 +319,24 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Recency boost (experimental)')
|
||||||
|
.setDesc('Files that have been modified more recently than [selected cutoff] are given a higher rank.')
|
||||||
|
.addDropdown(dropdown =>
|
||||||
|
dropdown
|
||||||
|
.addOptions({
|
||||||
|
[RecencyCutoff.Disabled]: 'Disabled',
|
||||||
|
[RecencyCutoff.Day]: '24 hours',
|
||||||
|
[RecencyCutoff.Week]: '7 days',
|
||||||
|
[RecencyCutoff.Month]: '30 days',
|
||||||
|
})
|
||||||
|
.setValue(settings.recencyBoost)
|
||||||
|
.onChange(async v => {
|
||||||
|
settings.recencyBoost = v as RecencyCutoff
|
||||||
|
await saveSettings(this.plugin)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
// Downranked files
|
// Downranked files
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Folders to downrank in search results')
|
.setName('Folders to downrank in search results')
|
||||||
@@ -398,7 +418,9 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
// Set Vim like navigation keys
|
// Set Vim like navigation keys
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Set Vim like navigation keys')
|
.setName('Set Vim like navigation keys')
|
||||||
.setDesc(`Navigate down the results with ${getCtrlKeyLabel()} + J/N, or navigate up with ${getCtrlKeyLabel()} + K/P.`)
|
.setDesc(
|
||||||
|
`Navigate down the results with ${getCtrlKeyLabel()} + J/N, or navigate up with ${getCtrlKeyLabel()} + K/P.`
|
||||||
|
)
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle
|
toggle
|
||||||
.setValue(settings.vimLikeNavigationShortcut)
|
.setValue(settings.vimLikeNavigationShortcut)
|
||||||
@@ -793,6 +815,7 @@ export function getDefaultSettings(app: App): OmnisearchSettings {
|
|||||||
return {
|
return {
|
||||||
useCache: true,
|
useCache: true,
|
||||||
hideExcluded: false,
|
hideExcluded: false,
|
||||||
|
recencyBoost: RecencyCutoff.Disabled,
|
||||||
downrankedFoldersFilters: [] as string[],
|
downrankedFoldersFilters: [] as string[],
|
||||||
ignoreDiacritics: true,
|
ignoreDiacritics: true,
|
||||||
ignoreArabicDiacritics: false,
|
ignoreArabicDiacritics: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user