Skip to content

Commit

Permalink
ContentElements are now all associated with a ContentType, which is m…
Browse files Browse the repository at this point in the history
…ore stable to distinguish elements than doing so based on a class using reflection.

Signed-off-by: Ralph Gasser <[email protected]>
  • Loading branch information
ppanopticon committed Dec 28, 2023
1 parent 1e608a3 commit 8765618
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.vitrivr.engine.core.model.content

/**
* An enumeration of the type of content that can be processed by vitrivr-engine.
*
* @author Ralph Gasser
* @version 1.0.0
*/
enum class ContentType {
/** A bitmap image (e.g., extracted from a video or image file). */
BITMAP_IMAGE,

/** An audio frame (e.g., extracted from a video or audio file). */
AUDIO_FRAME,

/** Text (e.g., extracted from a document). */
TEXT,

/** A 3D mesh. */
MESH
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.vitrivr.engine.core.model.content.element

import org.vitrivr.engine.core.model.content.ContentType
import java.nio.ShortBuffer

/**
Expand All @@ -19,4 +20,8 @@ interface AudioContent: ContentElement<ShortBuffer> {

/** The sampling rate of the data encoded in this [AudioContent]. */
val samplingRate: Int

/** The [ContentType] of an [AudioContent] is always [ContentType.AUDIO_FRAME]. */
override val type: ContentType
get() = ContentType.AUDIO_FRAME
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.vitrivr.engine.core.model.content.element

import org.vitrivr.engine.core.model.content.Content
import org.vitrivr.engine.core.model.content.ContentType

/**
* A [Content] element is a piece of [Content] that is tied to some actual [Content].
Expand All @@ -17,4 +18,7 @@ sealed interface ContentElement<T>: Content {
* @return [ContentElement]
*/
val content: T

/** The [ContentType] of this [ContentElement]. */
val type: ContentType
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.vitrivr.engine.core.model.content.element

import org.vitrivr.engine.core.model.content.ContentType
import java.awt.image.BufferedImage

/**
Expand All @@ -17,4 +18,8 @@ interface ImageContent: ContentElement<BufferedImage> {
/** Height of the [BufferedImage] held by this [ContentElement]. */
val height: Int
get() = this.content.height

/** The [ContentType] of an [ImageContent] is always [ContentType.BITMAP_IMAGE]. */
override val type: ContentType
get() = ContentType.BITMAP_IMAGE
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.vitrivr.engine.core.model.content.element

import org.vitrivr.engine.core.model.content.ContentType

/**
* A textual [ContentElement].
*
Expand All @@ -11,4 +13,8 @@ interface TextContent: ContentElement<String> {
/** Length of the [String] held by this [TextContent]. */
val length: Int
get() = this.content.length

/** The [ContentType] of an [TextContent] is always [ContentType.TEXT]. */
override val type: ContentType
get() = ContentType.TEXT
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ class CenterContentAggregator : AggregatorFactory {
* The [Instance] returns by the [AggregatorFactory]
*/
private class Instance(override val input: Operator<Retrievable>, context: IndexContext) : AbstractAggregator(input, context) {
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> = content.groupBy {
it::class
}.mapNotNull { (_, elements) ->
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> = content.groupBy { it.type }.mapNotNull { (_, elements) ->
if (elements.isNotEmpty()) {
elements[Math.floorDiv(elements.size, 2)]
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ class FirstContentAggregator : AggregatorFactory {
* The [Instance] returns by the [AggregatorFactory]
*/
private class Instance(override val input: Operator<Retrievable>, context: IndexContext) : AbstractAggregator(input, context) {
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> = content.groupBy { it::class }.mapNotNull { (_, elements) -> elements.firstOrNull() }
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> = content.groupBy { it.type }.mapNotNull { (_, elements) -> elements.firstOrNull() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ class LastContentAggregator : AggregatorFactory {
* The [Instance] returns by the [AggregatorFactory]
*/
private class Instance(override val input: Operator<Retrievable>, context: IndexContext) : AbstractAggregator(input, context) {
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> = content.groupBy { it::class }.mapNotNull { (_, elements) -> elements.lastOrNull() }
override fun aggregate(content: List<ContentElement<*>>): List<ContentElement<*>> = content.groupBy { it.type }.mapNotNull { (_, elements) -> elements.lastOrNull() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import org.vitrivr.engine.core.context.IndexContext
import org.vitrivr.engine.core.model.content.ContentType
import org.vitrivr.engine.core.model.content.decorators.SourcedContent
import org.vitrivr.engine.core.model.content.element.ContentElement
import org.vitrivr.engine.core.operators.Operator
import org.vitrivr.engine.core.operators.ingest.Decoder
import org.vitrivr.engine.core.operators.ingest.Transformer
import org.vitrivr.engine.core.operators.ingest.TransformerFactory
import org.vitrivr.engine.core.source.Source
import kotlin.reflect.KClass

/**
* A [Transformer] that samples the input [Flow] and only passes through every n-th element.
Expand All @@ -25,17 +25,17 @@ class ContentSamplingTransformer : TransformerFactory {

private class Instance(override val input: Operator<ContentElement<*>>, private val sample: Int) : Transformer {
override fun toFlow(scope: CoroutineScope): Flow<ContentElement<*>> {
val sources = mutableMapOf<KClass<out ContentElement<*>>, Source>()
val counters = mutableMapOf<KClass<out ContentElement<*>>, Int>()
val sources = mutableMapOf<ContentType, Source>()
val counters = mutableMapOf<ContentType, Int>()
return this.input.toFlow(scope).filter { value: ContentElement<*> ->
if (value is SourcedContent) { /* Only source content can be sampled. */
val clazz = value::class
if (sources[clazz] == null || sources[clazz] != value.source) {
sources[clazz] = value.source
counters[clazz] = 0
val type = value.type
if (sources[type] == null || sources[type] != value.source) {
sources[type] = value.source
counters[type] = 0
}
val pass = (counters[clazz]!! % this.sample == 0)
counters[clazz] = counters[clazz]!! + 1
val pass = (counters[type]!! % this.sample == 0)
counters[type] = counters[type]!! + 1
pass
} else {
true
Expand Down

0 comments on commit 8765618

Please sign in to comment.