#151 - User-defined boosted fields
This commit is contained in:
@@ -188,6 +188,7 @@ export class Omnisearch {
|
|||||||
headings1: settings.weightH1,
|
headings1: settings.weightH1,
|
||||||
headings2: settings.weightH2,
|
headings2: settings.weightH2,
|
||||||
headings3: settings.weightH3,
|
headings3: settings.weightH3,
|
||||||
|
tags: settings.weightUnmarkedTags,
|
||||||
unmarkedTags: settings.weightUnmarkedTags,
|
unmarkedTags: settings.weightUnmarkedTags,
|
||||||
},
|
},
|
||||||
// The query is already tokenized, don't tokenize again
|
// The query is already tokenized, don't tokenize again
|
||||||
@@ -232,6 +233,11 @@ export class Omnisearch {
|
|||||||
return results.filter(r => r.id === options.singleFilePath)
|
return results.filter(r => r.id === options.singleFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logDebug(
|
||||||
|
'searching with downranked folders',
|
||||||
|
settings.downrankedFoldersFilters
|
||||||
|
)
|
||||||
|
|
||||||
// Hide or downrank files that are in Obsidian's excluded list
|
// Hide or downrank files that are in Obsidian's excluded list
|
||||||
if (settings.hideExcluded) {
|
if (settings.hideExcluded) {
|
||||||
// Filter the files out
|
// Filter the files out
|
||||||
@@ -254,14 +260,13 @@ export class Omnisearch {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
logDebug(
|
// Extract tags from the query
|
||||||
'searching with downranked folders',
|
const tags = query.getTags()
|
||||||
settings.downrankedFoldersFilters
|
|
||||||
)
|
for (const result of results) {
|
||||||
// downrank files that are in folders listed in the downrankedFoldersFilters
|
const path = result.id
|
||||||
if (settings.downrankedFoldersFilters.length > 0) {
|
if (settings.downrankedFoldersFilters.length > 0) {
|
||||||
results.forEach(result => {
|
// downrank files that are in folders listed in the downrankedFoldersFilters
|
||||||
const path = result.id
|
|
||||||
let downrankingFolder = false
|
let downrankingFolder = false
|
||||||
settings.downrankedFoldersFilters.forEach(filter => {
|
settings.downrankedFoldersFilters.forEach(filter => {
|
||||||
if (path.startsWith(filter)) {
|
if (path.startsWith(filter)) {
|
||||||
@@ -285,21 +290,27 @@ export class Omnisearch {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Extract tags from the query
|
// Boost custom properties
|
||||||
const tags = query.getTags()
|
const metadata = app.metadataCache.getCache(path)
|
||||||
|
if (metadata) {
|
||||||
|
for (const { name, weight } of settings.weightCustomProperties) {
|
||||||
|
const values = metadata?.frontmatter?.[name]
|
||||||
|
if (values && result.terms.some(t => values.includes(t))) {
|
||||||
|
logDebug(`Boosting field "${name}" x${weight} for ${path}`)
|
||||||
|
result.score *= weight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Put the results with tags on top
|
// Put the results with tags on top
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
for (const result of results) {
|
|
||||||
if ((result.tags ?? []).includes(tag)) {
|
if ((result.tags ?? []).includes(tag)) {
|
||||||
result.score *= 100
|
result.score *= 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logDebug('Sorting and limiting results')
|
logDebug('Sorting and limiting results')
|
||||||
|
|
||||||
// Sort results and keep the 50 best
|
// Sort results and keep the 50 best
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// noinspection CssUnresolvedCustomProperty
|
||||||
import {
|
import {
|
||||||
Notice,
|
Notice,
|
||||||
Platform,
|
Platform,
|
||||||
@@ -25,6 +26,7 @@ interface WeightingSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface OmnisearchSettings extends WeightingSettings {
|
export interface OmnisearchSettings extends WeightingSettings {
|
||||||
|
weightCustomProperties: { name: string; weight: number }[]
|
||||||
/** Enables caching to speed up indexing */
|
/** Enables caching to speed up indexing */
|
||||||
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 */
|
||||||
@@ -100,7 +102,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Settings main title
|
// Settings main title
|
||||||
containerEl.createEl('h2', { text: 'Omnisearch' })
|
containerEl.createEl('h1', { text: 'Omnisearch' })
|
||||||
|
|
||||||
// Sponsor link - Thank you!
|
// Sponsor link - Thank you!
|
||||||
const divSponsor = containerEl.createDiv()
|
const divSponsor = containerEl.createDiv()
|
||||||
@@ -131,7 +133,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
// PDF Indexing
|
// PDF Indexing
|
||||||
const indexPDFsDesc = new DocumentFragment()
|
const indexPDFsDesc = new DocumentFragment()
|
||||||
indexPDFsDesc.createSpan({}, span => {
|
indexPDFsDesc.createSpan({}, span => {
|
||||||
span.innerHTML = `Omnisearch will use Text Extractor to index the content of your PDFs`
|
span.innerHTML = `Omnisearch will use Text Extractor to index the content of your PDFs.`
|
||||||
})
|
})
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(
|
.setName(
|
||||||
@@ -150,7 +152,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
// Images Indexing
|
// Images Indexing
|
||||||
const indexImagesDesc = new DocumentFragment()
|
const indexImagesDesc = new DocumentFragment()
|
||||||
indexImagesDesc.createSpan({}, span => {
|
indexImagesDesc.createSpan({}, span => {
|
||||||
span.innerHTML = `Omnisearch will use Text Extractor to OCR your images and index their content`
|
span.innerHTML = `Omnisearch will use Text Extractor to OCR your images and index their content.`
|
||||||
})
|
})
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(`Images OCR indexing ${getTextExtractor() ? '' : '⚠️ Disabled'}`)
|
.setName(`Images OCR indexing ${getTextExtractor() ? '' : '⚠️ Disabled'}`)
|
||||||
@@ -167,7 +169,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
// Office Documents Indexing
|
// Office Documents Indexing
|
||||||
const indexOfficesDesc = new DocumentFragment()
|
const indexOfficesDesc = new DocumentFragment()
|
||||||
indexOfficesDesc.createSpan({}, span => {
|
indexOfficesDesc.createSpan({}, span => {
|
||||||
span.innerHTML = `Omnisearch will use Text Extractor to index the content of your office documents (currently <pre style="display:inline">.docx</pre> and <pre style="display:inline">.xlsx</pre>)`
|
span.innerHTML = `Omnisearch will use Text Extractor to index the content of your office documents (currently <pre style="display:inline">.docx</pre> and <pre style="display:inline">.xlsx</pre>).`
|
||||||
})
|
})
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(
|
.setName(
|
||||||
@@ -189,7 +191,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
span.innerHTML = `
|
span.innerHTML = `
|
||||||
Omnisearch can index file<strong>names</strong> of "unsupported" files, such as e.g. <pre style="display:inline">.mp4</pre>
|
Omnisearch can index file<strong>names</strong> of "unsupported" files, such as e.g. <pre style="display:inline">.mp4</pre>
|
||||||
or non-extracted PDFs & images.<br/>
|
or non-extracted PDFs & images.<br/>
|
||||||
"Obsidian setting" will respect the value of "Files & Links > Detect all file extensions"`
|
"Obsidian setting" will respect the value of "Files & Links > Detect all file extensions".`
|
||||||
})
|
})
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Index paths of unsupported files')
|
.setName('Index paths of unsupported files')
|
||||||
@@ -262,7 +264,7 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
.setName('Respect Obsidian\'s "Excluded Files"')
|
.setName('Respect Obsidian\'s "Excluded Files"')
|
||||||
.setDesc(
|
.setDesc(
|
||||||
`By default, files that are in Obsidian\'s "Options > Files & Links > Excluded Files" list are downranked in results.
|
`By default, files that are in Obsidian\'s "Options > Files & Links > Excluded Files" list are downranked in results.
|
||||||
Enable this option to completely hide them`
|
Enable this option to completely hide them.`
|
||||||
)
|
)
|
||||||
.addToggle(toggle =>
|
.addToggle(toggle =>
|
||||||
toggle.setValue(settings.hideExcluded).onChange(async v => {
|
toggle.setValue(settings.hideExcluded).onChange(async v => {
|
||||||
@@ -495,10 +497,63 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName(
|
.setName(
|
||||||
`Tags without the # (default: ${DEFAULT_SETTINGS.weightUnmarkedTags})`
|
`Tags (default: ${DEFAULT_SETTINGS.weightUnmarkedTags})`
|
||||||
)
|
)
|
||||||
.addSlider(cb => this.weightSlider(cb, 'weightUnmarkedTags'))
|
.addSlider(cb => this.weightSlider(cb, 'weightUnmarkedTags'))
|
||||||
|
|
||||||
|
//#region Specific tags
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Header properties fields')
|
||||||
|
.setDesc('You can set custom weights for values of header properties (e.g. "keywords").')
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < settings.weightCustomProperties.length; i++) {
|
||||||
|
const item = settings.weightCustomProperties[i]
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName((i + 1).toString() + '.')
|
||||||
|
// TODO: add autocompletion from app.metadataCache.getAllPropertyInfos()
|
||||||
|
.addText(text => {
|
||||||
|
text
|
||||||
|
.setPlaceholder('Property name')
|
||||||
|
.setValue(item.name)
|
||||||
|
.onChange(async v => {
|
||||||
|
item.name = v
|
||||||
|
await saveSettings(this.plugin)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.addSlider(cb => {
|
||||||
|
cb.setLimits(1, 5, 0.1)
|
||||||
|
.setValue(item.weight)
|
||||||
|
.setDynamicTooltip()
|
||||||
|
.onChange(async v => {
|
||||||
|
item.weight = v
|
||||||
|
await saveSettings(this.plugin)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// Remove the tag
|
||||||
|
.addButton(btn => {
|
||||||
|
btn.setButtonText('Remove')
|
||||||
|
btn.onClick(async () => {
|
||||||
|
settings.weightCustomProperties.splice(i, 1)
|
||||||
|
await saveSettings(this.plugin)
|
||||||
|
this.display()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new custom tag
|
||||||
|
new Setting(containerEl)
|
||||||
|
.addButton(btn => {
|
||||||
|
btn.setButtonText('Add a new property')
|
||||||
|
btn.onClick(cb => {
|
||||||
|
settings.weightCustomProperties.push({ name: '', weight: 1 })
|
||||||
|
this.display()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//#endregion Specific tags
|
||||||
|
|
||||||
//#endregion Results Weighting
|
//#endregion Results Weighting
|
||||||
|
|
||||||
//#region HTTP Server
|
//#region HTTP Server
|
||||||
@@ -632,9 +687,9 @@ export class SettingsTab extends PluginSettingTab {
|
|||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Clear cache data')
|
.setName('Clear cache data')
|
||||||
.setDesc(resetCacheDesc)
|
.setDesc(resetCacheDesc)
|
||||||
.addButton(cb => {
|
.addButton(btn => {
|
||||||
cb.setButtonText('Clear cache')
|
btn.setButtonText('Clear cache')
|
||||||
cb.onClick(async () => {
|
btn.onClick(async () => {
|
||||||
await database.clearCache()
|
await database.clearCache()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -683,6 +738,7 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = {
|
|||||||
weightH2: 1.3,
|
weightH2: 1.3,
|
||||||
weightH3: 1.1,
|
weightH3: 1.1,
|
||||||
weightUnmarkedTags: 1.1,
|
weightUnmarkedTags: 1.1,
|
||||||
|
weightCustomProperties: [] as { name: string; weight: number }[],
|
||||||
|
|
||||||
httpApiEnabled: false,
|
httpApiEnabled: false,
|
||||||
httpApiPort: '51361',
|
httpApiPort: '51361',
|
||||||
|
|||||||
Reference in New Issue
Block a user