Fixed #48 - Highly favor tags in search results

This commit is contained in:
Simon Cambier
2022-06-17 19:56:10 +02:00
parent 21f936e4ee
commit 6e604988f4
4 changed files with 38 additions and 2 deletions

View File

@@ -27,6 +27,7 @@ export type IndexedNote = {
content: string content: string
aliases: string aliases: string
tags: string[],
headings1: string headings1: string
headings2: string headings2: string
headings3: string headings3: string

View File

@@ -1,5 +1,5 @@
import { Notice, TAbstractFile, TFile } from 'obsidian' import { Notice, TAbstractFile, TFile } from 'obsidian'
import MiniSearch, { type SearchResult } from 'minisearch' import MiniSearch, { type Options, type SearchResult } from 'minisearch'
import { import {
chsRegex, chsRegex,
SPACE_OR_PUNCTUATION, SPACE_OR_PUNCTUATION,
@@ -10,6 +10,7 @@ import {
import { import {
extractHeadingsFromCache, extractHeadingsFromCache,
getAliasesFromMetadata, getAliasesFromMetadata,
getTagsFromMetadata,
removeDiacritics, removeDiacritics,
stringsToRegex, stringsToRegex,
stripMarkdownCharacters, stripMarkdownCharacters,
@@ -51,7 +52,7 @@ const tokenize = (text: string): string[] => {
* and adds all the notes to the index * and adds all the notes to the index
*/ */
export async function initGlobalSearchIndex(): Promise<void> { export async function initGlobalSearchIndex(): Promise<void> {
const options = { const options: Options<IndexedNote> = {
tokenize, tokenize,
processTerm: (term: string) => processTerm: (term: string) =>
(settings.ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(), (settings.ignoreDiacritics ? removeDiacritics(term) : term).toLowerCase(),
@@ -64,6 +65,7 @@ export async function initGlobalSearchIndex(): Promise<void> {
'headings2', 'headings2',
'headings3', 'headings3',
], ],
storeFields: ['tags'],
} }
if ( if (
@@ -234,6 +236,18 @@ export async function getSuggestions(
} }
else { else {
results = results.slice(0, 50) results = results.slice(0, 50)
// Put the results with tags on top
const tags = query.segments
.filter(s => s.value.startsWith('#'))
.map(s => s.value)
for (const tag of tags) {
for (const result of results) {
if (result.tags.includes(tag)) {
result.score *= 100
}
}
}
} }
// Map the raw results to get usable suggestions // Map the raw results to get usable suggestions
@@ -243,6 +257,10 @@ export async function getSuggestions(
throw new Error(`Note "${result.id}" not indexed`) throw new Error(`Note "${result.id}" not indexed`)
} }
// Remove '#' from tags, for highlighting
query.segments.forEach(s => {
s.value = s.value.replace(/^#/, '')
})
// Clean search matches that match quoted expressions, // Clean search matches that match quoted expressions,
// and inject those expressions instead // and inject those expressions instead
const foundWords = [ const foundWords = [
@@ -251,6 +269,7 @@ export async function getSuggestions(
), ),
...query.segments.filter(s => s.exact).map(s => s.value), ...query.segments.filter(s => s.exact).map(s => s.value),
] ]
const matches = getMatches(note.content, stringsToRegex(foundWords)) const matches = getMatches(note.content, stringsToRegex(foundWords))
const resultNote: ResultNote = { const resultNote: ResultNote = {
score: result.score, score: result.score,
@@ -307,6 +326,7 @@ export async function addToIndex(file: TAbstractFile): Promise<void> {
path: file.path, path: file.path,
mtime: file.stat.mtime, mtime: file.stat.mtime,
tags: getTagsFromMetadata(metadata),
aliases: getAliasesFromMetadata(metadata).join(''), aliases: getAliasesFromMetadata(metadata).join(''),
headings1: metadata headings1: metadata
? extractHeadingsFromCache(metadata, 1).join(' ') ? extractHeadingsFromCache(metadata, 1).join(' ')

1
src/types.d.ts vendored
View File

@@ -7,6 +7,7 @@ declare module 'obsidian' {
interface FrontMatterCache { interface FrontMatterCache {
aliases?: string[] | string aliases?: string[] | string
tags?: string[] | string
} }
interface ViewState { interface ViewState {

View File

@@ -144,6 +144,20 @@ export function getAliasesFromMetadata(
.filter(s => !!s) .filter(s => !!s)
} }
export function getTagsFromMetadata(metadata: CachedMetadata | null): string[] {
const arrOrString = metadata?.frontmatter?.tags ?? []
const fromFrontMatter = (
Array.isArray(arrOrString) ? arrOrString : arrOrString.split(',')
)
.map(s => (s ? s.trim() : s))
.filter(s => !!s)
const fromBody = (metadata?.tags ?? []).map(t => t.tag)
return [...fromFrontMatter, ...fromBody].map(t =>
t[0] !== '#' ? '#' + t : t,
)
}
/** /**
* https://stackoverflow.com/a/37511463 * https://stackoverflow.com/a/37511463
*/ */