diff --git a/build.sbt b/build.sbt index e472e2c70..f4b02dc01 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,5 @@ -import ElasticsearchPluginPlugin.autoImport._ +import ElasticsearchPluginPlugin.autoImport.* +import org.typelevel.scalacoptions.* Global / scalaVersion := "2.13.12" @@ -8,7 +9,6 @@ lazy val Elastic4sVersion = "8.11.0" lazy val ElastiknnVersion = IO.read(file("version")).strip() lazy val LuceneVersion = "9.8.0" -lazy val ScalacOptions = List("-Xfatal-warnings", "-Ywarn-unused:imports") lazy val TestSettings = Seq( Test / parallelExecution := false, Test / logBuffered := false, @@ -16,6 +16,13 @@ lazy val TestSettings = Seq( libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.17" % Test ) +lazy val TpolecatSettings = Seq( + Test / tpolecatExcludeOptions ++= Set( + ScalacOptions.warnNonUnitStatement, + ScalacOptions.warnNumericWiden + ) +) + lazy val `elastiknn-root` = project .in(file(".")) .settings( @@ -40,7 +47,7 @@ lazy val `elastiknn-api4s` = project "org.elasticsearch" % "elasticsearch-x-content" % ElasticsearchVersion, "io.circe" %% "circe-parser" % CirceVersion % Test ), - scalacOptions ++= ScalacOptions, + TpolecatSettings, TestSettings ) @@ -53,7 +60,7 @@ lazy val `elastiknn-client-elastic4s` = project libraryDependencies ++= Seq( "com.sksamuel.elastic4s" %% "elastic4s-client-esjava" % Elastic4sVersion ), - scalacOptions ++= ScalacOptions, + TpolecatSettings, TestSettings ) @@ -67,7 +74,7 @@ lazy val `elastiknn-lucene` = project "org.apache.lucene" % "lucene-core" % LuceneVersion, "org.apache.lucene" % "lucene-analysis-common" % LuceneVersion % Test ), - scalacOptions ++= ScalacOptions, + TpolecatSettings, TestSettings ) @@ -85,7 +92,7 @@ lazy val `elastiknn-models` = project "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED" ), - scalacOptions ++= ScalacOptions, + TpolecatSettings, TestSettings ) @@ -94,7 +101,8 @@ lazy val `elastiknn-models-benchmarks` = project .dependsOn(`elastiknn-models`, `elastiknn-api4s`) .enablePlugins(JmhPlugin) .settings( - Jmh / javaOptions ++= Seq("--add-modules", "jdk.incubator.vector") + Jmh / javaOptions ++= Seq("--add-modules", "jdk.incubator.vector"), + TpolecatSettings ) lazy val `elastiknn-plugin` = project @@ -124,7 +132,7 @@ lazy val `elastiknn-plugin` = project "ch.qos.logback" % "logback-classic" % "1.4.11" % Test, "com.klibisz.futil" %% "futil" % "0.1.2" % Test ), - scalacOptions ++= ScalacOptions, + TpolecatSettings, TestSettings ) @@ -132,6 +140,6 @@ lazy val `elastiknn-plugin-integration-tests` = project .in(file("elastiknn-plugin-integration-tests")) .dependsOn(`elastiknn-plugin` % "test->test") .settings( - scalacOptions ++= ScalacOptions, + TpolecatSettings, TestSettings ) diff --git a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Mapping.scala b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Mapping.scala new file mode 100644 index 000000000..7fba01bae --- /dev/null +++ b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Mapping.scala @@ -0,0 +1,21 @@ +package com.klibisz.elastiknn.api + +sealed trait Mapping { + def dims: Int +} + +object Mapping { + final case class SparseBool(dims: Int) extends Mapping + + final case class JaccardLsh(dims: Int, L: Int, k: Int) extends Mapping + + final case class HammingLsh(dims: Int, L: Int, k: Int) extends Mapping + + final case class DenseFloat(dims: Int) extends Mapping + + final case class CosineLsh(dims: Int, L: Int, k: Int) extends Mapping + + final case class L2Lsh(dims: Int, L: Int, k: Int, w: Int) extends Mapping + + final case class PermutationLsh(dims: Int, k: Int, repeating: Boolean) extends Mapping +} \ No newline at end of file diff --git a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/NearestNeighborsQuery.scala b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/NearestNeighborsQuery.scala new file mode 100644 index 000000000..3e0051e03 --- /dev/null +++ b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/NearestNeighborsQuery.scala @@ -0,0 +1,62 @@ +package com.klibisz.elastiknn.api + +sealed trait NearestNeighborsQuery { + def field: String + + def vec: Vec + + def similarity: Similarity + + def withVec(v: Vec): NearestNeighborsQuery +} + +object NearestNeighborsQuery { + sealed trait ApproximateQuery extends NearestNeighborsQuery { + def candidates: Int + + def withCandidates(candidates: Int): ApproximateQuery + } + + final case class Exact(field: String, similarity: Similarity, vec: Vec = Vec.Empty()) extends NearestNeighborsQuery { + override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) + } + + final case class CosineLsh(field: String, candidates: Int, vec: Vec = Vec.Empty()) extends ApproximateQuery { + override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) + + override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) + + override def similarity: Similarity = Similarity.Cosine + } + + final case class HammingLsh(field: String, candidates: Int, vec: Vec = Vec.Empty()) extends ApproximateQuery { + override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) + + override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) + + override def similarity: Similarity = Similarity.Hamming + } + + final case class JaccardLsh(field: String, candidates: Int, vec: Vec = Vec.Empty()) extends ApproximateQuery { + override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) + + override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) + + override def similarity: Similarity = Similarity.Jaccard + } + + final case class L2Lsh(field: String, candidates: Int, probes: Int = 0, vec: Vec = Vec.Empty()) extends ApproximateQuery { + override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) + + override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) + + override def similarity: Similarity = Similarity.L2 + } + + final case class PermutationLsh(field: String, similarity: Similarity, candidates: Int, vec: Vec = Vec.Empty()) + extends ApproximateQuery { + override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) + + override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) + } +} \ No newline at end of file diff --git a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Similarity.scala b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Similarity.scala new file mode 100644 index 000000000..405a1af3f --- /dev/null +++ b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Similarity.scala @@ -0,0 +1,17 @@ +package com.klibisz.elastiknn.api + +sealed trait Similarity + +object Similarity { + case object Cosine extends Similarity + + case object Hamming extends Similarity + + case object Jaccard extends Similarity + + case object L1 extends Similarity + + case object L2 extends Similarity + + val values: Seq[Similarity] = Vector(Cosine, Jaccard, Hamming, L1, L2) +} diff --git a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Vec.scala b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Vec.scala new file mode 100644 index 000000000..539cb7e5e --- /dev/null +++ b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/Vec.scala @@ -0,0 +1,89 @@ +package com.klibisz.elastiknn.api + +import scala.annotation.tailrec +import scala.util.Random + +sealed trait Vec + +object Vec { + + sealed trait KnownDims { + this: Vec => + def dims: Int + } + + final case class SparseBool(trueIndices: Array[Int], totalIndices: Int) extends Vec with KnownDims { + def sorted(): SparseBool = copy(trueIndices.sorted) + + def isSorted: Boolean = { + @tailrec + def check(i: Int): Boolean = + if (i == trueIndices.length) true + else if (trueIndices(i) < trueIndices(i - 1)) false + else check(i + 1) + + check(1) + } + + override def equals(other: Any): Boolean = other match { + case other: SparseBool => (trueIndices sameElements other.trueIndices) && totalIndices == other.totalIndices + case _ => false + } + + override def toString: String = s"SparseBool(${trueIndices.take(3).mkString(",")},...,${trueIndices.length}/$totalIndices)" + + def dims: Int = totalIndices + } + + object SparseBool { + + def random(totalIndices: Int, bias: Double = 0.5)(implicit rng: Random): SparseBool = { + var trueIndices = Array.empty[Int] + (0 until totalIndices).foreach(i => if (rng.nextDouble() <= bias) trueIndices :+= i else ()) + SparseBool(trueIndices, totalIndices) + } + + def randoms(totalIndices: Int, n: Int, bias: Double = 0.5)(implicit rng: Random): Vector[SparseBool] = + (0 until n).map(_ => random(totalIndices, bias)).toVector + } + + final case class DenseFloat(values: Array[Float]) extends Vec with KnownDims { + override def equals(other: Any): Boolean = other match { + case other: DenseFloat => other.values sameElements values + case _ => false + } + + override def toString: String = s"DenseFloat(${values.take(3).map(n => f"$n%.2f").mkString(",")},...,${values.length})" + + def dot(other: DenseFloat): Float = { + var (i, dp) = (0, 0f) + while (i < other.values.length) { + dp += (other.values(i) * values(i)) + i += 1 + } + dp + } + + override def dims: Int = values.length + } + + object DenseFloat { + def apply(values: Float*): DenseFloat = DenseFloat(values.toArray) + + def random(length: Int, unit: Boolean = false, scale: Int = 1)(implicit rng: Random): DenseFloat = { + val v = DenseFloat((0 until length).toArray.map(_ => rng.nextGaussian().toFloat * scale)) + if (unit) { + val norm = math.sqrt(v.values.map(x => x * x).sum.toDouble).toFloat + DenseFloat(v.values.map(_ / norm)) + } else v + } + + def randoms(length: Int, n: Int, unit: Boolean = false, scale: Int = 1)(implicit rng: Random): Vector[DenseFloat] = + (0 until n).map(_ => random(length, unit, scale)).toVector + } + + final case class Indexed(index: String, id: String, field: String) extends Vec + + final case class Empty() extends Vec + +} diff --git a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/XContentCodec.scala b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/XContentCodec.scala index 5be52dfcf..500d77fef 100644 --- a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/XContentCodec.scala +++ b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/XContentCodec.scala @@ -31,12 +31,13 @@ object XContentCodec { encodeElastiknnObject(t, b) b.field(Names.TYPE, vectorType) b.endObject() + () } } private val xcJson = XContentType.JSON.xContent() - def encodeUnsafe[T](t: T, b: XContentBuilder)(implicit c: Encoder[T]): Unit = + private def encodeUnsafe[T](t: T, b: XContentBuilder)(implicit c: Encoder[T]): Unit = c.encodeUnsafe(t, b) def encodeUnsafeToByteArray[T](t: T)(implicit c: Encoder[T]): Array[Byte] = { @@ -90,6 +91,7 @@ object XContentCodec { case Similarity.L2 => b.value(Names.L2) case Similarity.Cosine => b.value(Names.COSINE) } + () } } @@ -98,6 +100,7 @@ object XContentCodec { b.startObject() b.array(Names.VALUES, t.values) b.endObject() + () } } @@ -107,6 +110,7 @@ object XContentCodec { b.field(Names.TOTAL_INDICES, t.totalIndices) b.array(Names.TRUE_INDICES, t.trueIndices) b.endObject() + () } } @@ -114,6 +118,7 @@ object XContentCodec { override def encodeUnsafe(t: Vec.Empty, b: XContentBuilder): Unit = { b.startObject() b.endObject() + () } } @@ -124,6 +129,7 @@ object XContentCodec { b.field(Names.ID, t.id) b.field(Names.INDEX, t.index) b.endObject() + () } } @@ -144,6 +150,7 @@ object XContentCodec { b.field(Names.DIMS, t.dims) b.field(Names.MODEL, Names.EXACT) b.endObject() + () } } @@ -157,6 +164,7 @@ object XContentCodec { b.field(Names.MODEL, Names.LSH) b.field(Names.SIMILARITY, Names.JACCARD) b.endObject() + () } } @@ -170,6 +178,7 @@ object XContentCodec { b.field(Names.MODEL, Names.LSH) b.field(Names.SIMILARITY, Names.HAMMING) b.endObject() + () } } @@ -180,6 +189,7 @@ object XContentCodec { b.field(Names.DIMS, t.dims) b.field(Names.MODEL, Names.EXACT) b.endObject() + () } } @@ -193,6 +203,7 @@ object XContentCodec { b.field(Names.MODEL, Names.LSH) b.field(Names.SIMILARITY, Names.COSINE) b.endObject() + () } } @@ -207,6 +218,7 @@ object XContentCodec { b.field(Names.SIMILARITY, Names.L2) b.field(Names.LSH_W, t.w) b.endObject() + () } } @@ -219,6 +231,7 @@ object XContentCodec { b.field(Names.MODEL, Names.PERMUTATION_LSH) b.field(Names.REPEATING, t.repeating) b.endObject() + () } } @@ -255,6 +268,7 @@ object XContentCodec { b.field(Names.VEC) vec.encodeUnsafe(t.vec, b) b.endObject() + () } } @@ -269,6 +283,7 @@ object XContentCodec { b.field(Names.VEC) vec.encodeUnsafe(t.vec, b) b.endObject() + () } } @@ -283,6 +298,7 @@ object XContentCodec { b.field(Names.VEC) vec.encodeUnsafe(t.vec, b) b.endObject() + () } } @@ -297,6 +313,7 @@ object XContentCodec { b.field(Names.VEC) vec.encodeUnsafe(t.vec, b) b.endObject() + () } } @@ -312,6 +329,7 @@ object XContentCodec { b.field(Names.VEC) vec.encodeUnsafe(t.vec, b) b.endObject() + () } } @@ -326,6 +344,7 @@ object XContentCodec { b.field(Names.VEC) vec.encodeUnsafe(t.vec, b) b.endObject() + () } } diff --git a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/package.scala b/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/package.scala deleted file mode 100644 index 3b638aa17..000000000 --- a/elastiknn-api4s/src/main/scala/com/klibisz/elastiknn/api/package.scala +++ /dev/null @@ -1,160 +0,0 @@ -package com.klibisz.elastiknn - -import scala.annotation.tailrec -import scala.util.Random - -package object api { - sealed trait Similarity - object Similarity { - case object Cosine extends Similarity - case object Hamming extends Similarity - case object Jaccard extends Similarity - case object L1 extends Similarity - case object L2 extends Similarity - val values: Seq[Similarity] = Vector(Cosine, Jaccard, Hamming, L1, L2) - } - - sealed trait Vec - - object Vec { - - sealed trait KnownDims { - this: Vec => - def dims: Int - } - - final case class SparseBool(trueIndices: Array[Int], totalIndices: Int) extends Vec with KnownDims { - def sorted(): SparseBool = copy(trueIndices.sorted) - - def isSorted: Boolean = { - @tailrec - def check(i: Int): Boolean = - if (i == trueIndices.length) true - else if (trueIndices(i) < trueIndices(i - 1)) false - else check(i + 1) - check(1) - } - - override def equals(other: Any): Boolean = other match { - case other: SparseBool => (trueIndices sameElements other.trueIndices) && totalIndices == other.totalIndices - case _ => false - } - - override def toString: String = s"SparseBool(${trueIndices.take(3).mkString(",")},...,${trueIndices.length}/$totalIndices)" - - def dims: Int = totalIndices - } - - object SparseBool { - - def random(totalIndices: Int, bias: Double = 0.5)(implicit rng: Random): SparseBool = { - var trueIndices = Array.empty[Int] - (0 until totalIndices).foreach(i => if (rng.nextDouble() <= bias) trueIndices :+= i else ()) - SparseBool(trueIndices, totalIndices) - } - - def randoms(totalIndices: Int, n: Int, bias: Double = 0.5)(implicit rng: Random): Vector[SparseBool] = - (0 until n).map(_ => random(totalIndices, bias)).toVector - } - - final case class DenseFloat(values: Array[Float]) extends Vec with KnownDims { - override def equals(other: Any): Boolean = other match { - case other: DenseFloat => other.values sameElements values - case _ => false - } - - override def toString: String = s"DenseFloat(${values.take(3).map(n => f"$n%.2f").mkString(",")},...,${values.length})" - - def dot(other: DenseFloat): Float = { - var (i, dp) = (0, 0f) - while (i < other.values.length) { - dp += (other.values(i) * values(i)) - i += 1 - } - dp - } - - override def dims: Int = values.length - } - - object DenseFloat { - def apply(values: Float*): DenseFloat = DenseFloat(values.toArray) - - def random(length: Int, unit: Boolean = false, scale: Int = 1)(implicit rng: Random): DenseFloat = { - val v = DenseFloat((0 until length).toArray.map(_ => rng.nextGaussian().toFloat * scale)) - if (unit) { - val norm = math.sqrt(v.values.map(x => x * x).sum).toFloat - DenseFloat(v.values.map(_ / norm)) - } else v - } - - def randoms(length: Int, n: Int, unit: Boolean = false, scale: Int = 1)(implicit rng: Random): Vector[DenseFloat] = - (0 until n).map(_ => random(length, unit, scale)).toVector - } - - final case class Indexed(index: String, id: String, field: String) extends Vec - - final case class Empty() extends Vec - - } - - sealed trait Mapping { - def dims: Int - } - object Mapping { - final case class SparseBool(dims: Int) extends Mapping - final case class JaccardLsh(dims: Int, L: Int, k: Int) extends Mapping - final case class HammingLsh(dims: Int, L: Int, k: Int) extends Mapping - final case class DenseFloat(dims: Int) extends Mapping - final case class CosineLsh(dims: Int, L: Int, k: Int) extends Mapping - final case class L2Lsh(dims: Int, L: Int, k: Int, w: Int) extends Mapping - final case class PermutationLsh(dims: Int, k: Int, repeating: Boolean) extends Mapping - } - - sealed trait NearestNeighborsQuery { - def field: String - def vec: Vec - def similarity: Similarity - def withVec(v: Vec): NearestNeighborsQuery - } - object NearestNeighborsQuery { - sealed trait ApproximateQuery extends NearestNeighborsQuery { - def candidates: Int - def withCandidates(candidates: Int): ApproximateQuery - } - - final case class Exact(field: String, similarity: Similarity, vec: Vec = Vec.Empty()) extends NearestNeighborsQuery { - override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) - } - - final case class CosineLsh(field: String, candidates: Int, vec: Vec = Vec.Empty()) extends ApproximateQuery { - override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) - override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) - override def similarity: Similarity = Similarity.Cosine - } - - final case class HammingLsh(field: String, candidates: Int, vec: Vec = Vec.Empty()) extends ApproximateQuery { - override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) - override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) - override def similarity: Similarity = Similarity.Hamming - } - - final case class JaccardLsh(field: String, candidates: Int, vec: Vec = Vec.Empty()) extends ApproximateQuery { - override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) - override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) - override def similarity: Similarity = Similarity.Jaccard - } - - final case class L2Lsh(field: String, candidates: Int, probes: Int = 0, vec: Vec = Vec.Empty()) extends ApproximateQuery { - override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) - override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) - override def similarity: Similarity = Similarity.L2 - } - - final case class PermutationLsh(field: String, similarity: Similarity, candidates: Int, vec: Vec = Vec.Empty()) - extends ApproximateQuery { - override def withVec(v: Vec): NearestNeighborsQuery = copy(vec = v) - override def withCandidates(candidates: Int): ApproximateQuery = copy(candidates = candidates) - } - } -} diff --git a/elastiknn-client-elastic4s/src/main/scala/com/klibisz/elastiknn/client/Elastic4sCompatibility.scala b/elastiknn-client-elastic4s/src/main/scala/com/klibisz/elastiknn/client/Elastic4sCompatibility.scala index 147757f66..d12fe4a0c 100644 --- a/elastiknn-client-elastic4s/src/main/scala/com/klibisz/elastiknn/client/Elastic4sCompatibility.scala +++ b/elastiknn-client-elastic4s/src/main/scala/com/klibisz/elastiknn/client/Elastic4sCompatibility.scala @@ -3,8 +3,6 @@ package com.klibisz.elastiknn.client import com.klibisz.elastiknn.api.{NearestNeighborsQuery, XContentCodec} import com.sksamuel.elastic4s.requests.searches.queries.{Query, RawQuery} -import scala.language.implicitConversions - trait Elastic4sCompatibility { implicit def convertQuery(nnq: NearestNeighborsQuery): Query = nnq.toQuery diff --git a/elastiknn-lucene/src/test/scala/com/klibisz/elastiknn/lucene/LuceneSupport.scala b/elastiknn-lucene/src/test/scala/com/klibisz/elastiknn/lucene/LuceneSupport.scala index 47d7b07e6..4a8ff20f2 100644 --- a/elastiknn-lucene/src/test/scala/com/klibisz/elastiknn/lucene/LuceneSupport.scala +++ b/elastiknn-lucene/src/test/scala/com/klibisz/elastiknn/lucene/LuceneSupport.scala @@ -32,6 +32,7 @@ trait LuceneSupport { } finally { indexWriter.close() tmpDir.delete() + () } res } diff --git a/elastiknn-models-benchmarks/src/main/scala/com/klibisz/elastiknn/vectors/VectorOpsJmhBenchmark.scala b/elastiknn-models-benchmarks/src/main/scala/com/klibisz/elastiknn/vectors/VectorOpsJmhBenchmark.scala index dfc38ee49..9c153ac1b 100644 --- a/elastiknn-models-benchmarks/src/main/scala/com/klibisz/elastiknn/vectors/VectorOpsJmhBenchmark.scala +++ b/elastiknn-models-benchmarks/src/main/scala/com/klibisz/elastiknn/vectors/VectorOpsJmhBenchmark.scala @@ -7,7 +7,7 @@ import scala.util.Random @State(Scope.Benchmark) class BenchmarkState { - implicit private val rng = new Random(0) + implicit private val rng: Random = new Random(0) val v1 = Vec.DenseFloat.random(999).values val v2 = Vec.DenseFloat.random(999).values val panama = new PanamaFloatVectorOps @@ -21,7 +21,7 @@ class VectorOpsJmhBenchmark { @Fork(value = 1) @Warmup(time = 5, iterations = 6) @Measurement(time = 5, iterations = 6) - def cosineSimilarityPanama(state: BenchmarkState): Unit = + def cosineSimilarityPanama(state: BenchmarkState): Double = state.panama.cosineSimilarity(state.v1, state.v2) @Benchmark @@ -45,7 +45,7 @@ class VectorOpsJmhBenchmark { @Fork(value = 1) @Warmup(time = 5, iterations = 6) @Measurement(time = 5, iterations = 6) - def dotProductPanama(state: BenchmarkState): Unit = + def dotProductPanama(state: BenchmarkState): Double = state.panama.dotProduct(state.v1, state.v2) @Benchmark @@ -53,7 +53,7 @@ class VectorOpsJmhBenchmark { @Fork(value = 1) @Warmup(time = 5, iterations = 6) @Measurement(time = 5, iterations = 6) - def l1DistancePanama(state: BenchmarkState): Unit = + def l1DistancePanama(state: BenchmarkState): Double = state.panama.l1Distance(state.v1, state.v2) @Benchmark @@ -69,7 +69,7 @@ class VectorOpsJmhBenchmark { @Fork(value = 1) @Warmup(time = 5, iterations = 6) @Measurement(time = 5, iterations = 6) - def l2DistancePanama(state: BenchmarkState): Unit = + def l2DistancePanama(state: BenchmarkState): Double = state.panama.l2Distance(state.v1, state.v2) @Benchmark diff --git a/elastiknn-plugin-integration-tests/src/test/scala/com/klibisz/elastiknn/TestData.scala b/elastiknn-plugin-integration-tests/src/test/scala/com/klibisz/elastiknn/TestData.scala index 6fc833852..6ba20e64b 100644 --- a/elastiknn-plugin-integration-tests/src/test/scala/com/klibisz/elastiknn/TestData.scala +++ b/elastiknn-plugin-integration-tests/src/test/scala/com/klibisz/elastiknn/TestData.scala @@ -61,8 +61,8 @@ object TestData extends XContentCodecCirceBridge { val l1 = new ExactSimilarityFunction.L1(new PanamaFloatVectorOps) val l2 = new ExactSimilarityFunction.L2(new PanamaFloatVectorOps) val cos = new ExactSimilarityFunction.Cosine(new PanamaFloatVectorOps) - val corpus = Vec.DenseFloat.randoms(dims, numCorpus) - val queries = Vec.DenseFloat.randoms(dims, numQueries).map { qv => + val corpus = Vec.DenseFloat.randoms(dims, numCorpus, unit) + val queries = Vec.DenseFloat.randoms(dims, numQueries, unit).map { qv => Query( qv, Seq( diff --git a/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/mapper/VectorMapper.scala b/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/mapper/VectorMapper.scala index de4d8397b..fc22f4108 100644 --- a/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/mapper/VectorMapper.scala +++ b/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/mapper/VectorMapper.scala @@ -88,7 +88,7 @@ object VectorMapper { } } -abstract class VectorMapper[V <: Vec: XContentCodec.Decoder: XContentCodec.Encoder] { self => +abstract class VectorMapper[V <: Vec: XContentCodec.Decoder] { self => def CONTENT_TYPE: String def checkAndCreateFields(mapping: Mapping, field: String, vec: V): Try[Seq[IndexableField]] diff --git a/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/query/ElastiknnQueryBuilder.scala b/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/query/ElastiknnQueryBuilder.scala index 7ffa0e868..c612f097b 100644 --- a/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/query/ElastiknnQueryBuilder.scala +++ b/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/query/ElastiknnQueryBuilder.scala @@ -9,7 +9,6 @@ import com.klibisz.elastiknn.vectors.FloatVectorOps import org.elasticsearch.index.mapper.MappedFieldType import org.elasticsearch.index.query.SearchExecutionContext -import scala.language.implicitConversions import scala.util.{Failure, Success, Try} final class ElastiknnQueryBuilder(floatVectorOps: FloatVectorOps, modelCache: ModelCache) { diff --git a/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/storage/StoredVec.scala b/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/storage/StoredVec.scala index 7354a3575..c7065c772 100644 --- a/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/storage/StoredVec.scala +++ b/elastiknn-plugin/src/main/scala/com/klibisz/elastiknn/storage/StoredVec.scala @@ -4,7 +4,6 @@ import java.util import com.klibisz.elastiknn.api.Vec -import scala.language.implicitConversions /** Abstraction for different vector storage layouts and typeclasses for encoding/decoding them. * This is decoupled from the api Vec case classes so we can support various optimizations that might change the diff --git a/project/plugins.sbt b/project/plugins.sbt index 514aeb2e2..06185fbe1 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +1,3 @@ addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.6") +addSbtPlugin("org.typelevel" % "sbt-tpolecat" % "0.5.0") +