diff --git a/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/model/retrievable/attributes/ScoreAttribute.kt b/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/model/retrievable/attributes/ScoreAttribute.kt index 21e277c6..173ee12c 100644 --- a/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/model/retrievable/attributes/ScoreAttribute.kt +++ b/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/model/retrievable/attributes/ScoreAttribute.kt @@ -8,21 +8,36 @@ import kotlin.math.max * Scores are expected to be in the range of [0, 1]. * * @author Luca Rossetto - * @version 1.0.0 + * @author Ralph Gasser + * @version 1.1.0 */ -data class ScoreAttribute(val score: Float) : MergingRetrievableAttribute { +sealed interface ScoreAttribute : MergingRetrievableAttribute { - companion object { - val ZERO = ScoreAttribute(0f) - } + /** The score associated with this [ScoreAttribute]. */ + val score: Float - constructor(score: Double) : this(score.toFloat()) + /** + * A similarity score. Strictly bound between 0 and 1. + */ + data class Similarity(override val score: Float): ScoreAttribute { + init { + require(score in 0f..1f) { "Similarity score '$score' outside of valid range (0, 1)" } + } - init { - require(score in 0f..1f) { "Score '$score' outside of valid range (0, 1)" } + override fun merge(other: MergingRetrievableAttribute): Similarity = Similarity( + max(this.score, (other as? Similarity)?.score ?: 0f) + ) } - override fun merge(other: MergingRetrievableAttribute): ScoreAttribute = ScoreAttribute( - max(this.score, (other as? ScoreAttribute)?.score ?: 0f) - ) + /** + * An unbound score. Strictly bound between 0 and 1. + */ + data class Unbound(override val score: Float): ScoreAttribute { + init { + require(this.score >= 0f) { "Score '$score' outside of valid range (>= 0)." } + } + override fun merge(other: MergingRetrievableAttribute): Unbound = Unbound( + max(this.score, (other as? Unbound)?.score ?: 0f) + ) + } } diff --git a/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/util/math/ScoringFunctions.kt b/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/util/math/ScoringFunctions.kt index 839241df..7222536c 100644 --- a/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/util/math/ScoringFunctions.kt +++ b/vitrivr-engine-core/src/main/kotlin/org/vitrivr/engine/core/util/math/ScoringFunctions.kt @@ -19,7 +19,7 @@ object ScoringFunctions { * @param max Maximum value. Default is 1.0. */ fun max(retrieved: Retrieved, max: Float = 1.0f): ScoreAttribute { - val distance = retrieved.filteredAttribute()?.distance ?: return ScoreAttribute.ZERO - return ScoreAttribute(max - distance) + val distance = retrieved.filteredAttribute()?.distance ?: return ScoreAttribute.Unbound(0.0f) + return ScoreAttribute.Unbound(max - distance) } } \ No newline at end of file diff --git a/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/string/StringDescriptorReader.kt b/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/string/StringDescriptorReader.kt index a65b1670..45483618 100644 --- a/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/string/StringDescriptorReader.kt +++ b/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/string/StringDescriptorReader.kt @@ -47,7 +47,7 @@ class StringDescriptorReader(field: Schema.Field<*, StringDescriptor>, connectio val retrievableId = tuple.asUuidValue(RETRIEVABLE_ID_COLUMN_NAME)?.value ?: throw IllegalArgumentException("The provided tuple is missing the required field '${RETRIEVABLE_ID_COLUMN_NAME}'.") val score = tuple.asDouble(SCORE_COLUMN_NAME) ?: 0.0 val retrieved = Retrieved(retrievableId, null, false) - retrieved.addAttribute(ScoreAttribute(score)) + retrieved.addAttribute(ScoreAttribute.Unbound(score.toFloat())) retrieved } } diff --git a/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/struct/StructDescriptorReader.kt b/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/struct/StructDescriptorReader.kt index 05ffa440..1b2eab53 100644 --- a/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/struct/StructDescriptorReader.kt +++ b/vitrivr-engine-module-cottontaildb/src/main/kotlin/org/vitrivr/engine/plugin/cottontaildb/descriptors/struct/StructDescriptorReader.kt @@ -65,7 +65,7 @@ class StructDescriptorReader(field: Schema.Field<*, StructDescriptor>, connectio val retrievableId = tuple.asUuidValue(RETRIEVABLE_ID_COLUMN_NAME)?.value ?: throw IllegalArgumentException("The provided tuple is missing the required field '${RETRIEVABLE_ID_COLUMN_NAME}'.") val score = tuple.asDouble(SCORE_COLUMN_NAME) ?: 0.0 val retrieved = Retrieved(retrievableId, null, false) - retrieved.addAttribute(ScoreAttribute(score)) + retrieved.addAttribute(ScoreAttribute.Unbound(score.toFloat())) retrieved } } diff --git a/vitrivr-engine-module-features/src/main/kotlin/org/vitrivr/engine/base/features/averagecolor/AverageColorRetriever.kt b/vitrivr-engine-module-features/src/main/kotlin/org/vitrivr/engine/base/features/averagecolor/AverageColorRetriever.kt index 2a986f59..e93a5888 100644 --- a/vitrivr-engine-module-features/src/main/kotlin/org/vitrivr/engine/base/features/averagecolor/AverageColorRetriever.kt +++ b/vitrivr-engine-module-features/src/main/kotlin/org/vitrivr/engine/base/features/averagecolor/AverageColorRetriever.kt @@ -36,7 +36,7 @@ class AverageColorRetriever( override fun toFlow(scope: CoroutineScope) = flow { val reader = this@AverageColorRetriever.field.getReader() reader.getAll(this@AverageColorRetriever.query).forEach { - it.addAttribute(ScoreAttribute(scoringFunction(it))) + it.addAttribute(ScoreAttribute.Similarity(scoringFunction(it))) emit(it) } } diff --git a/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/TemporalSequenceAggregator.kt b/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/TemporalSequenceAggregator.kt index 1cf1f57b..a063bd9f 100644 --- a/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/TemporalSequenceAggregator.kt +++ b/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/TemporalSequenceAggregator.kt @@ -195,7 +195,7 @@ class TemporalSequenceAggregator( id, "temporalSequence", true ) - retrieved.addAttribute(ScoreAttribute(score)) + retrieved.addAttribute(ScoreAttribute.Unbound(score)) retrieved.addAttribute(RelationshipAttribute(relationships)) emit(retrieved) diff --git a/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/WeightedScoreFusion.kt b/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/WeightedScoreFusion.kt index b4c27d1d..139bcc4a 100644 --- a/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/WeightedScoreFusion.kt +++ b/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/aggregate/WeightedScoreFusion.kt @@ -70,7 +70,7 @@ class WeightedScoreFusion( //make a copy and override score val retrieved = first.copy() retrieved.filteredAttribute() - retrieved.addAttribute(ScoreAttribute(score)) + retrieved.addAttribute(ScoreAttribute.Unbound(score)) emit(retrieved) diff --git a/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/transform/ScoreAggregator.kt b/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/transform/ScoreAggregator.kt index cc85f22b..2144127f 100644 --- a/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/transform/ScoreAggregator.kt +++ b/vitrivr-engine-query/src/main/kotlin/org/vitrivr/engine/query/transform/ScoreAggregator.kt @@ -46,10 +46,10 @@ class ScoreAggregator( } } - retrieved.addAttribute(ScoreAttribute(score)) + retrieved.addAttribute(ScoreAttribute.Unbound(score)) } else { - retrieved.addAttribute(ScoreAttribute(0f)) + retrieved.addAttribute(ScoreAttribute.Unbound(0f)) } retrieved