Skip to content

Commit

Permalink
Merge branch 'master' into update/elasticsearch-rest-client-8.11.0
Browse files Browse the repository at this point in the history
  • Loading branch information
sksamuel authored Nov 12, 2023
2 parents ffc9902 + 258bd75 commit 5b63507
Show file tree
Hide file tree
Showing 21 changed files with 276 additions and 48 deletions.
61 changes: 31 additions & 30 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.sksamuel.elastic4s

import com.sksamuel.elastic4s.api.{AggregationApi, AliasesApi, AnalyzeApi, AnalyzerApi, BulkApi, CatsApi, ClearRolesCacheApi, ClusterApi, CollapseApi, CountApi, CreateIndexApi, CreateRoleApi, CreateUserApi, DeleteApi, DeleteIndexApi, DeleteRoleApi, DeleteUserApi, ExistsApi, ExplainApi, ForceMergeApi, GetApi, HighlightApi, IndexAdminApi, IndexApi, IndexRecoveryApi, IndexTemplateApi, IngestApi, KnnApi, LocksApi, MappingApi, NodesApi, NormalizerApi, PipelineAggregationApi, QueryApi, ReindexApi, RoleApi, ScoreApi, ScriptApi, ScrollApi, SearchApi, SearchTemplateApi, SettingsApi, SnapshotApi, SortApi, StoredScriptApi, SuggestionApi, TaskApi, TermVectorApi, TokenFilterApi, TokenizerApi, TypesApi, UpdateApi, UserAdminApi, UserApi, ValidateApi}
import com.sksamuel.elastic4s.api.{AggregationApi, AliasesApi, AnalyzeApi, AnalyzerApi, BulkApi, CatsApi, ClearRolesCacheApi, ClusterApi, CollapseApi, CountApi, CreateIndexApi, CreateRoleApi, CreateUserApi, DeleteApi, DeleteIndexApi, DeleteRoleApi, DeleteUserApi, ExistsApi, ExplainApi, ForceMergeApi, GetApi, HighlightApi, IndexAdminApi, IndexApi, IndexRecoveryApi, IndexTemplateApi, IngestApi, KnnApi, LocksApi, MappingApi, NodesApi, NormalizerApi, PipelineAggregationApi, PitApi, QueryApi, ReindexApi, RoleApi, ScoreApi, ScriptApi, ScrollApi, SearchApi, SearchTemplateApi, SettingsApi, SnapshotApi, SortApi, StoredScriptApi, SuggestionApi, TaskApi, TermVectorApi, TokenFilterApi, TokenizerApi, TypesApi, UpdateApi, UserAdminApi, UserApi, ValidateApi}

import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
Expand Down Expand Up @@ -61,7 +61,8 @@ trait ElasticApi
with UserAdminApi
with UserApi
with ValidateApi
with KnnApi {
with KnnApi
with PitApi {

implicit class RichFuture[T](future: Future[T]) {
def await(implicit duration: Duration = 60.seconds): T = Await.result(future, duration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.sksamuel.elastic4s.handlers.index.mapping.MappingHandlers
import com.sksamuel.elastic4s.handlers.index.{IndexAdminHandlers, IndexHandlers, IndexStatsHandlers, IndexTemplateHandlers, RolloverHandlers}
import com.sksamuel.elastic4s.handlers.locks.LocksHandlers
import com.sksamuel.elastic4s.handlers.nodes.NodesHandlers
import com.sksamuel.elastic4s.handlers.pit.PitHandlers
import com.sksamuel.elastic4s.handlers.reindex.ReindexHandlers
import com.sksamuel.elastic4s.handlers.script.StoredScriptHandlers
import com.sksamuel.elastic4s.handlers.security.roles.{RoleAdminHandlers, RoleHandlers}
Expand Down Expand Up @@ -63,7 +64,8 @@ with TaskHandlers
with TermVectorHandlers
with UserAdminHandlers
with UserHandlers
with ValidateHandlers {
with ValidateHandlers
with PitHandlers {

implicit class RichRequest[T](t: T) {
def request(implicit handler: Handler[T, _]): ElasticRequest = handler.build(t)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sksamuel.elastic4s.api

import com.sksamuel.elastic4s.Index
import com.sksamuel.elastic4s.requests.pit.{CreatePitRequest, DeletePitRequest}

trait PitApi {
def createPointInTime(index: Index): CreatePitRequest = CreatePitRequest(index)

def deletePointInTime(id: String) : DeletePitRequest = DeletePitRequest(id)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.sksamuel.elastic4s.requests.searches.queries.compound.BoolQuery
import com.sksamuel.elastic4s.requests.searches.queries.funcscorer.FunctionScoreQuery
import com.sksamuel.elastic4s.requests.searches.queries.geo.{GeoBoundingBoxQuery, GeoDistanceQuery, GeoPolygonQuery, GeoShapeQuery, Shape}
import com.sksamuel.elastic4s.requests.searches.queries.matches.{MatchAllQuery, MatchBoolPrefixQuery, MatchNoneQuery, MatchPhrasePrefixQuery, MatchPhraseQuery, MatchQuery, MultiMatchQuery}
import com.sksamuel.elastic4s.requests.searches.queries.{ArtificialDocument, BoostingQuery, CombinedFieldsQuery, ConstantScore, DisMaxQuery, DistanceFeatureQuery, ExistsQuery, FuzzyQuery, HasChildQuery, HasParentQuery, IdQuery, IntervalsQuery, IntervalsRule, MoreLikeThisItem, MoreLikeThisQuery, MultiTermQuery, NestedQuery, PercolateQuery, PinnedQuery, PrefixQuery, Query, QueryStringQuery, RangeQuery, RankFeatureQuery, RawQuery, RegexQuery, ScriptQuery, SimpleStringQuery}
import com.sksamuel.elastic4s.requests.searches.queries.{ArtificialDocument, BoostingQuery, CombinedFieldsQuery, ConstantScore, DisMaxQuery, DistanceFeatureQuery, ExistsQuery, FuzzyQuery, HasChildQuery, HasParentQuery, IdQuery, IntervalsQuery, IntervalsRule, MoreLikeThisItem, MoreLikeThisQuery, MultiTermQuery, NestedQuery, PercolateQuery, PinnedQuery, PrefixQuery, Query, QueryStringQuery, RangeQuery, RankFeatureQuery, RawQuery, RegexQuery, ScriptQuery, ScriptScoreQuery, SimpleStringQuery}
import com.sksamuel.elastic4s.requests.searches.span.{SpanContainingQuery, SpanFieldMaskingQuery, SpanFirstQuery, SpanMultiTermQuery, SpanNearQuery, SpanNotQuery, SpanOrQuery, SpanQuery, SpanTermQuery, SpanWithinQuery}
import com.sksamuel.elastic4s.requests.searches.term.{TermQuery, TermsLookupQuery, TermsQuery, TermsSetQuery, WildcardQuery}
import com.sksamuel.elastic4s.requests.searches.{GeoPoint, ScoreMode, TermsLookup, span, term}
Expand Down Expand Up @@ -191,6 +191,9 @@ trait QueryApi {
def scriptQuery(script: Script): ScriptQuery = ScriptQuery(script)
def scriptQuery(script: String): ScriptQuery = ScriptQuery(script)

def scriptScoreQuery(): ScriptScoreQuery = ScriptScoreQuery()
def scriptScoreQuery(query: Query): ScriptScoreQuery = ScriptScoreQuery().query(query)

def simpleStringQuery(q: String): SimpleStringQuery = SimpleStringQuery(q)
def stringQuery(q: String): QueryStringQuery = QueryStringQuery(q)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ object SearchBodyBuilderFn {
if (request.searchAfter.nonEmpty)
builder.autoarray("search_after", request.searchAfter)

request.pit.foreach{pit =>
builder.startObject("pit")
builder.field("id", pit.id)
pit.keepAlive.foreach{keepAlive =>
builder.field("keep_alive", s"${keepAlive.toSeconds}s")
}
builder.endObject()
}

if (request.scriptFields.nonEmpty) {
builder.startObject("script_fields")
request.scriptFields.foreach { field =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ trait SearchHandlers {

override def build(request: SearchRequest): ElasticRequest = {

val endpoint =
if (request.indexes.values.isEmpty)
val endpoint = {
if (request.indexes.values.isEmpty && request.pit.isDefined)
"/_search"
else if (request.indexes.values.isEmpty)
"/_all/_search"
else
"/" + request.indexes.values
.map(ElasticUrlEncoder.encodeUrlFragment)
.mkString(",") + "/_search"
}

val params = scala.collection.mutable.Map.empty[String, String]
request.requestCache.map(_.toString).foreach(params.put("request_cache", _))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.sksamuel.elastic4s.requests.pit

import com.sksamuel.elastic4s.Index

import scala.concurrent.duration.FiniteDuration

case class CreatePitRequest(index: Index, keepAlive: Option[FiniteDuration] = None) {
def keepAlive(keepAlive: FiniteDuration): CreatePitRequest = copy(keepAlive = Some(keepAlive))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.sksamuel.elastic4s.requests.pit

case class CreatePitResponse (id: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.sksamuel.elastic4s.requests.pit

case class DeletePitRequest(id: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.sksamuel.elastic4s.requests.pit

case class DeletePitResponse(succeeded: Boolean, num_freed: Int)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sksamuel.elastic4s.requests.searches

import scala.concurrent.duration.FiniteDuration

case class Pit(id: String, keepAlive: Option[FiniteDuration] = None) {
def keepAlive(keepAlive: FiniteDuration): Pit = copy(keepAlive = Some(keepAlive))
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ case class SearchRequest(indexes: Indexes,
runtimeMappings: Seq[RuntimeMapping] = Nil,
ext: Map[String, Any] = Map.empty,
knn: Option[Knn] = None,
multipleKnn: Seq[Knn] = Nil) {
multipleKnn: Seq[Knn] = Nil,
pit: Option[Pit] = None) {

/** Adds a single string query to this search
*
Expand Down Expand Up @@ -295,4 +296,9 @@ case class SearchRequest(indexes: Indexes,
def knn(knn: Knn): SearchRequest = copy(knn = knn.some)

def multipleKnn(multipleKnn: Iterable[Knn]): SearchRequest = copy(multipleKnn = multipleKnn.toSeq)

def pit(pit: Pit): SearchRequest = {
// When a pit is provided, no target must be given
copy(pit = Some(pit), indexes = Indexes(Nil))
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
package com.sksamuel.elastic4s.requests.searches.queries

case class ScriptScoreQuery(script: String) extends Query
import com.sksamuel.elastic4s.requests.script.Script

case class ScriptScoreQuery(query: Option[Query] = None, script: Option[Script] = None, minScore: Option[Double] = None, boost: Option[Double] = None) extends Query {
def boost(boost: Double): ScriptScoreQuery = copy(boost = Option(boost))
def minScore(min: Double): ScriptScoreQuery = copy(minScore = Option(min))
def query(query: Query): ScriptScoreQuery = copy(query = Some(query))
def script(script: Script): ScriptScoreQuery = copy(script = Some(script))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.sksamuel.elastic4s.handlers.pit

import com.sksamuel.elastic4s.json.{XContentBuilder, XContentFactory}
import com.sksamuel.elastic4s.requests.pit.DeletePitRequest

object DeletePitBuilderFn {
def apply(request: DeletePitRequest): XContentBuilder =
XContentFactory.jsonBuilder().field("id" , request.id)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.sksamuel.elastic4s.handlers.pit

import com.sksamuel.elastic4s.{ElasticRequest, Handler, HttpEntity}
import com.sksamuel.elastic4s.requests.pit.{CreatePitRequest, CreatePitResponse, DeletePitRequest, DeletePitResponse}

trait PitHandlers {
implicit object CreatePitHandler extends Handler[CreatePitRequest, CreatePitResponse] {

override def build(request: CreatePitRequest): ElasticRequest =
ElasticRequest(
method = "POST",
endpoint = s"/${request.index.name}/_pit",
params = request.keepAlive
.map(keepAlive => Map("keep_alive" -> s"${keepAlive.toSeconds}s"))
.getOrElse(Map.empty[String, String])
)
}

implicit object DeletePitHandler extends Handler[DeletePitRequest, DeletePitResponse] {

override def build(request: DeletePitRequest): ElasticRequest = {
val entity = HttpEntity(DeletePitBuilderFn(request).string, "application/json")
ElasticRequest(
method = "DELETE",
endpoint = s"/_pit",
entity
)
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import com.sksamuel.elastic4s.requests.searches.queries.compound.BoolQuery
import com.sksamuel.elastic4s.requests.searches.queries.funcscorer.{FunctionScoreQuery, ScriptScore}
import com.sksamuel.elastic4s.requests.searches.queries.geo.{GeoBoundingBoxQuery, GeoDistanceQuery, GeoPolygonQuery, GeoShapeQuery}
import com.sksamuel.elastic4s.requests.searches.queries.matches.{MatchAllQuery, MatchBoolPrefixQuery, MatchNoneQuery, MatchPhrasePrefixQuery, MatchPhraseQuery, MatchQuery, MultiMatchQuery}
import com.sksamuel.elastic4s.requests.searches.queries.{BoostingQuery, CombinedFieldsQuery, ConstantScore, DisMaxQuery, DistanceFeatureQuery, ExistsQuery, FuzzyQuery, HasChildQuery, HasParentQuery, IdQuery, IntervalsQuery, MoreLikeThisQuery, NestedQuery, NoopQuery, ParentIdQuery, PercolateQuery, PinnedQuery, PrefixQuery, Query, QueryStringQuery, RangeQuery, RankFeatureQuery, RawQuery, RegexQuery, ScriptQuery, SimpleStringQuery}
import com.sksamuel.elastic4s.requests.searches.queries.{BoostingQuery, CombinedFieldsQuery, ConstantScore, CustomQuery, DisMaxQuery, DistanceFeatureQuery, ExistsQuery, FuzzyQuery, HasChildQuery, HasParentQuery, IdQuery, IntervalsQuery, MoreLikeThisQuery, NestedQuery, NoopQuery, ParentIdQuery, PercolateQuery, PinnedQuery, PrefixQuery, Query, QueryStringQuery, RangeQuery, RankFeatureQuery, RawQuery, RegexQuery, ScriptQuery, ScriptScoreQuery, SimpleStringQuery}
import com.sksamuel.elastic4s.requests.searches.span.{SpanContainingQuery, SpanFieldMaskingQuery, SpanFirstQuery, SpanMultiTermQuery, SpanNearQuery, SpanNotQuery, SpanOrQuery, SpanTermQuery, SpanWithinQuery}
import com.sksamuel.elastic4s.requests.searches.term.{TermQuery, TermsLookupQuery, TermsQuery, TermsSetQuery, WildcardQuery}
import com.sksamuel.elastic4s.requests.searches.queries.CustomQuery

object QueryBuilderFn {
def apply(q: Query): XContentBuilder = q match {
Expand Down Expand Up @@ -56,7 +55,7 @@ object QueryBuilderFn {
case q: RawQuery => RawQueryBodyFn(q)
case q: RegexQuery => RegexQueryBodyFn(q)
case q: ScriptQuery => ScriptQueryBodyFn(q)
case q: ScriptScore => ScriptScoreQueryBodyFn(q)
case q: ScriptScoreQuery => ScriptScoreQueryBodyFn(q)
case s: SimpleStringQuery => SimpleStringBodyFn(s)
case s: SpanContainingQuery => SpanContainingQueryBodyFn(s)
case s: SpanFirstQuery => SpanFirstQueryBodyFn(s)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
package com.sksamuel.elastic4s.handlers.searches.queries

import com.sksamuel.elastic4s.handlers.script.ScriptBuilderFn
import com.sksamuel.elastic4s.json.{XContentBuilder, XContentFactory}
import com.sksamuel.elastic4s.requests.searches.queries.funcscorer.ScriptScore
import com.sksamuel.elastic4s.requests.searches.queries.ScriptScoreQuery

object ScriptScoreQueryBodyFn {

def apply(q: ScriptScore): XContentBuilder = {
def apply(q: ScriptScoreQuery): XContentBuilder = {
val builder = XContentFactory.jsonBuilder()
builder.rawField("script", q.script.script)
builder.startObject("script_score")
q.query.foreach(q => builder.rawField("query", QueryBuilderFn(q)))
q.script.foreach(s => builder.rawField("script", ScriptBuilderFn(s)))
q.boost.foreach(builder.field("boost", _))
q.minScore.foreach(builder.field("min_score", _))
builder.endObject()
builder
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.sksamuel.elastic4s.requests.pit

import com.sksamuel.elastic4s.testkit.DockerTests
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import scala.concurrent.duration.DurationInt
import scala.util.Try

class PitTests extends AnyFlatSpec with Matchers with DockerTests {

Try {
client.execute {
deleteIndex("pit")
}.await
}

client.execute {
createIndex("pit").mapping {
mapping(
textField("name").stored(true),
textField("brand").stored(true),
textField("ingredients").stored(true)
)
}
}.await

"A create pit request" should "create a pit" in {
val resp = client
.execute(createPointInTime("pit").keepAlive(30.seconds))
.await.result

resp.id.length should be > 0
}

"A delete pit request" should "delete a pit" in {
val pit = client
.execute(createPointInTime("pit").keepAlive(30.seconds))
.await.result

val result = client.execute(deletePointInTime(pit.id)).await.result

result.succeeded should be(true)
result.num_freed should be > 0
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.sksamuel.elastic4s.search.queries

import com.sksamuel.elastic4s.requests.script.Script
import com.sksamuel.elastic4s.testkit.DockerTests
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec

import scala.util.Try

class ScriptScoreQueryTest extends AnyWordSpec with DockerTests with Matchers {

Try {
client.execute {
deleteIndex("person")
}.await
}

client.execute(
bulk(
indexInto("person") fields(
"name" -> "reese",
"age" -> 1.0
),
indexInto("person") fields(
"name" -> "finch",
"age" -> 1.0
),
indexInto("person") fields(
"name" -> "finch",
"age" -> 2.0
),
indexInto("person") fields(
"name" -> "finch",
"age" -> 3.0
)
).refreshImmediately
).await

"script score query" should {
"filter by query" in {
client.execute {
search("person") query {
scriptScoreQuery(termQuery("name", "finch"))
.script(Script("doc['age'].value % 3"))
}
}.await.result.totalHits shouldBe 3
}
"rank by custom score" in {
client.execute {
search("person") query {
scriptScoreQuery(termQuery("name", "finch"))
.script(Script("doc['age'].value % 3"))
}
}.await.result.hits.hits.map(_.sourceAsString) shouldBe Array(
"""{"name":"finch","age":2.0}""",
"""{"name":"finch","age":1.0}""",
"""{"name":"finch","age":3.0}"""
)
}
"return correct custom score" in {
client.execute {
search("person") query {
scriptScoreQuery(termQuery("name", "finch"))
.script(Script("doc['age'].value % 3"))
}
}.await.result.hits.hits.map(_.score) shouldBe Array(2.0, 1.0, 0.0)
}
}
}
8 changes: 4 additions & 4 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ object Dependencies {
val JacksonVersion = "2.14.3"
val Json4sVersion = "4.0.6"
val Log4jVersion = "2.15.0"
val MockitoVersion = "5.6.0"
val MockitoVersion = "5.7.0"
val MonixVersion = "3.4.1"
val PekkoHttpVersion = "1.0.0"
val PekkoVersion = "1.0.1"
val PlayJsonVersion = "2.10.2"
val PlayJsonVersion = "2.10.3"
val ReactiveStreamsVersion = "1.0.3"
val ScalatestPlusMockitoArtifactId = "mockito-3-4"
val ScalatestPlusVersion = "3.2.9.0"
val ScalazVersion = "7.2.35"
val ScalatestVersion = "3.2.16"
val Slf4jVersion = "2.0.9"
val SprayJsonVersion = "1.3.6"
val SttpVersion = "3.8.16"
val SttpVersion = "3.9.1"
val ZIOJson1Version = "0.1.5"
val ZIO1Version = "1.0.18"
val ZIOVersion = "2.0.18"
val ZIOVersion = "2.0.19"
val ZIOJsonVersion = "0.6.2"

lazy val commonDeps = Seq(
Expand Down

0 comments on commit 5b63507

Please sign in to comment.