improvement: More stable search that prefers title

This commit is contained in:
Artem Chepurnyi 2024-09-29 12:43:52 +03:00
parent 390c999f65
commit b533c6a876
2 changed files with 39 additions and 21 deletions

View File

@ -929,10 +929,10 @@ fun vaultListScreenState(
},
)
val indexed = mutableListOf<SearchToken>()
indexed += SearchToken(
priority = 2f,
value = secret.name,
)
//indexed += SearchToken(
// priority = 2f,
// value = secret.name,
//)
if (secret.login != null) {
// Make username searchable
if (secret.login.username != null) {
@ -2005,7 +2005,8 @@ private suspend fun List<IndexedModel<VaultItem2.Item>>.search(
source = x.tokens,
query = queryComponents,
)
}.div(it.indexedOther.size.coerceAtLeast(1))
}
.div(it.indexedOther.size.coerceAtLeast(1))
val r = it.indexedText.find(
query = query,
colorBackground = highlightBackgroundColor,
@ -2014,15 +2015,24 @@ private suspend fun List<IndexedModel<VaultItem2.Item>>.search(
if (r == null && q <= 0.0001f) {
return@parallelSearch null
}
// Slightly prefer favorite items, but by a very small
// margin. The idea is that favorite items are show on top
// anyway, so if a user is using the search, then he probably
// searches for something other than the favorite items.
val favoriteScoreModifier = if (it.model.favourite) 1.35f else 1f
val finalScore = if (r != null) {
r.score + r.score * q / 10f
} else {
q / 15f
} * favoriteScoreModifier
FilteredModel(
model = it.model,
score = q + (r?.score ?: 0f),
score = finalScore,
result = r,
)
}
.sortedWith(
compareBy(
{ !it.model.favourite },
{ -it.score },
),
)

View File

@ -54,7 +54,7 @@ fun IndexedText.find(
return null
}
var x = query.components.map { false }.toMutableList()
val x = MutableList(query.components.size) { false }
var score = 0f
val text = buildAnnotatedString {
@ -77,14 +77,20 @@ fun IndexedText.find(
return@forEachIndexed
}
val queryPositionScore = 1f - i.toFloat() / comp.lowercase.length.toFloat()
val queryLengthScore =
queryComp.lowercase.length.toFloat() / comp.lowercase.length.toFloat()
val s = 0f +
queryPositionScore +
// We want to prefer results that start with a given query
val queryPositionScore = if (i == 0) { // starts with a query
1f
} else {
val penalty = 0.25f
val ratio = i.toFloat() / comp.lowercase.length.toFloat()
(1f - penalty) * (1f - ratio)
}
val queryLengthScore = queryComp.lowercase.length.toFloat()
val totalScore = 0f +
queryPositionScore *
queryLengthScore
if (s > max) {
max = s
if (totalScore > max) {
max = totalScore
// remember the position of the match, so we can draw it.
start = i
end = i + queryComp.lowercase.length
@ -104,19 +110,21 @@ fun IndexedText.find(
end = offset + end,
)
}
score += max *
// We want to prioritize when the component starts with
// a given query.
((1f - compIndex.toFloat() / components.size.toFloat()) / 5f + 0.8f)
val componentPositionScoreModifier = kotlin.run {
val compIndexNormalized = compIndex.toFloat() / components.size.toFloat()
(1f - compIndexNormalized) * 0.5f + 0.5f
}
score += max * componentPositionScoreModifier
}
if (score < 0.01f || !x.all { it } && requireAll) return null
if (score < 0.01f || requireAll && !x.all { it }) return null
}
return IndexedText.FindResult(
text = this.text,
components = this.components,
highlightedText = text,
score = score / components.size.toFloat(),
score = score / this.text.length.toFloat(),
)
}