Skip to content

Commit 9ad3bd9

Browse files
committed
Add store and index_options parameters to sparse vector field (#3521)
(cherry picked from commit 17feb25)
1 parent 32a9314 commit 9ad3bd9

File tree

4 files changed

+75
-12
lines changed

4 files changed

+75
-12
lines changed
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
package com.sksamuel.elastic4s.fields
22

3+
import com.sksamuel.elastic4s.requests.searches.queries.PruningConfig
4+
35
object SparseVectorField {
46
val `type`: String = "sparse_vector"
57
}
68

7-
case class SparseVectorField(name: String) extends ElasticField {
9+
case class SparseVectorIndexOptions(prune: Boolean, pruningConfig: Option[PruningConfig])
10+
11+
case class SparseVectorField(
12+
name: String,
13+
store: Boolean = false,
14+
indexOptions: Option[SparseVectorIndexOptions] = None
15+
) extends ElasticField {
816
override def `type`: String = SparseVectorField.`type`
917
}

elastic4s-handlers/src/main/scala/com/sksamuel/elastic4s/handlers/fields/SparseVectorFieldBuilderFn.scala

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,45 @@ package com.sksamuel.elastic4s.handlers.fields
22

33
import com.sksamuel.elastic4s.fields._
44
import com.sksamuel.elastic4s.json.{XContentBuilder, XContentFactory}
5+
import com.sksamuel.elastic4s.requests.searches.queries.PruningConfig
56

67
object SparseVectorFieldBuilderFn {
7-
def toField(name: String, values: Map[String, Any]): SparseVectorField = SparseVectorField(name)
8+
private def getPruningConfig(values: Map[String, Any]): PruningConfig =
9+
PruningConfig(
10+
values.get("tokens_freq_ratio_threshold").map(_.asInstanceOf[Int]),
11+
values.get("tokens_weight_threshold").map(_.asInstanceOf[Double].toFloat)
12+
)
13+
14+
private def getIndexOptions(values: Map[String, Any]): SparseVectorIndexOptions = {
15+
SparseVectorIndexOptions(
16+
values("prune").asInstanceOf[Boolean],
17+
pruningConfig = values.get("pruning_config").map(_.asInstanceOf[Map[String, Any]]).map(getPruningConfig)
18+
)
19+
}
20+
21+
def toField(name: String, values: Map[String, Any]): SparseVectorField = SparseVectorField(
22+
name,
23+
values("store").asInstanceOf[Boolean],
24+
indexOptions = values.get("index_options").map(_.asInstanceOf[Map[String, Any]]).map(getIndexOptions)
25+
)
826

927
def build(field: SparseVectorField): XContentBuilder = {
1028
val builder = XContentFactory.jsonBuilder()
1129
builder.field("type", field.`type`)
30+
builder.field("store", field.store)
31+
field.indexOptions.foreach { indexOptions =>
32+
builder.startObject("index_options")
33+
builder.field("prune", indexOptions.prune)
34+
indexOptions.pruningConfig.foreach { pruningConfig =>
35+
if (pruningConfig.tokensFreqRatioThreshold.nonEmpty || pruningConfig.tokensWeighThreshold.nonEmpty) {
36+
builder.startObject("pruning_config")
37+
pruningConfig.tokensFreqRatioThreshold.foreach(builder.field("tokens_freq_ratio_threshold", _))
38+
pruningConfig.tokensWeighThreshold.foreach(builder.field("tokens_weight_threshold", _))
39+
builder.endObject()
40+
}
41+
}
42+
builder.endObject()
43+
}
1244
builder.endObject()
1345
}
1446
}

elastic4s-tests/src/test/scala/com/sksamuel/elastic4s/fields/ElasticFieldBuilderFnTest.scala

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -246,16 +246,6 @@ class ElasticFieldBuilderFnTest extends AnyWordSpec with Matchers {
246246
JacksonSupport.mapper.readValue[Map[String, Any]](jsonString)
247247
) shouldBe field
248248
}
249-
250-
"support SparseVectorField" in {
251-
val field = SparseVectorField("sparse_vector_field")
252-
val jsonString = """{"type":"sparse_vector"}"""
253-
ElasticFieldBuilderFn(field).string shouldBe jsonString
254-
ElasticFieldBuilderFn.construct(
255-
field.name,
256-
JacksonSupport.mapper.readValue[Map[String, Any]](jsonString)
257-
) shouldBe field
258-
}
259249
"support RankFeaturesField with positive_score_impact" in {
260250
val field = RankFeaturesField("rank_features_field", positiveScoreImpact = Some(false))
261251
val jsonString = """{"type":"rank_features","positive_score_impact":false}"""
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.sksamuel.elastic4s.fields
2+
3+
import com.sksamuel.elastic4s.ElasticApi
4+
import com.sksamuel.elastic4s.handlers.fields.{ElasticFieldBuilderFn, SparseVectorFieldBuilderFn}
5+
import com.sksamuel.elastic4s.jackson.JacksonSupport
6+
import com.sksamuel.elastic4s.requests.searches.queries.PruningConfig
7+
import org.scalatest.flatspec.AnyFlatSpec
8+
import org.scalatest.matchers.should.Matchers
9+
10+
class SparseVectorFieldTest extends AnyFlatSpec with Matchers with ElasticApi {
11+
"A SparseVectorField" should "be minimally supported" in {
12+
val field = SparseVectorField("test.tokens")
13+
val jsonString = SparseVectorFieldBuilderFn.build(field).string
14+
jsonString shouldBe """{"type":"sparse_vector","store":false}"""
15+
ElasticFieldBuilderFn.construct(
16+
field.name,
17+
JacksonSupport.mapper.readValue[Map[String, Any]](jsonString)
18+
) shouldBe field
19+
}
20+
21+
it should "support all fields" in {
22+
val sparseVectorIndexOptions =
23+
SparseVectorIndexOptions(prune = true, pruningConfig = Some(PruningConfig(Some(5), Some(1.0F))))
24+
25+
val field = SparseVectorField("test.tokens", store = true, indexOptions = Some(sparseVectorIndexOptions))
26+
val jsonString = SparseVectorFieldBuilderFn.build(field).string
27+
jsonString shouldBe """{"type":"sparse_vector","store":true,"index_options":{"prune":true,"pruning_config":{"tokens_freq_ratio_threshold":5,"tokens_weight_threshold":1.0}}}"""
28+
ElasticFieldBuilderFn.construct(
29+
field.name,
30+
JacksonSupport.mapper.readValue[Map[String, Any]](jsonString)
31+
) shouldBe field
32+
}
33+
}

0 commit comments

Comments
 (0)