Feature/172 recency (#439)

* Fixed ts errors

* #172 - First draft at recency boost
This commit is contained in:
Simon Cambier
2025-02-01 18:47:36 +01:00
committed by GitHub
parent 9d7f4183cf
commit 84812771ec
4 changed files with 68 additions and 12 deletions

View File

@@ -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

View File

@@ -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 =

View File

@@ -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'
@@ -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(

View File

@@ -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,