From 39a6cf905b8e77f050881f9004ce4d31cd80247b Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 16:31:53 -0400 Subject: [PATCH 1/8] Fix date histogram cache miss: replace now with cacheable date bounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ES cannot cache filter bitsets for queries containing time-relative expressions like `now` or `now-2000y` — the value changes each millisecond, so ES skips the query cache entirely. With ~2,000 requests/minute each triggering a full BKD tree traversal of a 2,000-year date range, this drives ES nodes to 85–99% CPU. Replace relative lower bounds with fixed epoch dates (fully cacheable) and the `now` upper bound with `now/d` (rounds to current day, cached for up to 24 hours). Co-Authored-By: Claude Sonnet 4.6 --- .../dpla/api/v2/search/queryBuilders/QueryBuilder.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/dpla/api/v2/search/queryBuilders/QueryBuilder.scala b/src/main/scala/dpla/api/v2/search/queryBuilders/QueryBuilder.scala index 4e40e40..fdb47f8 100644 --- a/src/main/scala/dpla/api/v2/search/queryBuilders/QueryBuilder.scala +++ b/src/main/scala/dpla/api/v2/search/queryBuilders/QueryBuilder.scala @@ -334,8 +334,8 @@ trait QueryBuilder extends FieldDefinitions with DefaultJsonProtocol { } val gte = facet.split("\\.").lastOption match { - case Some("month") => "now-416y" - case _ => "now-2000y" + case Some("month") => "1600-01-01" + case _ => "0001-01-01" } val dateHistogram = JsObject( @@ -343,7 +343,7 @@ trait QueryBuilder extends FieldDefinitions with DefaultJsonProtocol { "range" -> JsObject( esField -> JsObject( "gte" -> gte.toJson, - "lte" -> "now".toJson + "lte" -> "now/d".toJson ) ) ), From 0b0b4769b9eec562c08e53129696f423cffaad7c Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:09:42 -0400 Subject: [PATCH 2/8] Bump sbt to 1.10.0 and fix plugin resolution --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index d91c272..b485f62 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.4.6 +sbt.version=1.10.0 \ No newline at end of file From bda66d170045a0bce79d97ae390bb10688966396 Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:09:47 -0400 Subject: [PATCH 3/8] Bump sbt-assembly to 2.3.1 and sbt-scoverage to 2.3.1 --- project/plugins.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index b4d3aa5..7aef9a2 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1") -addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "1.1.0") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3") \ No newline at end of file +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1") \ No newline at end of file From 321bc20d12d5c84638ea4733bd0087d69f8c9d9b Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:11:28 -0400 Subject: [PATCH 4/8] Revert sbt-scoverage to 1.9.3 (2.3.x lacks scalac plugin for Scala 2.13.4) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 7aef9a2..0c12ff5 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1") \ No newline at end of file +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3") \ No newline at end of file From 45c8f14041ebf3e8b922a33a3df004bb67f5b7a8 Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:13:04 -0400 Subject: [PATCH 5/8] Bump scalaVersion to 2.13.16 (required by sbt 1.10.0 SIP-51 enforcement) --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index ac3c498..91ea93c 100644 --- a/build.sbt +++ b/build.sbt @@ -17,7 +17,7 @@ lazy val root = (project in file(".")) .settings( inThisBuild(List( organization := "dpla", - scalaVersion := "2.13.4" + scalaVersion := "2.13.16" )), Defaults.itSettings, @@ -53,4 +53,4 @@ ThisBuild / assemblyMergeStrategy := { case "reference.conf" => MergeStrategy.concat case "META-INF/MANIFEST.MF" => MergeStrategy.discard case x => MergeStrategy.first -} +} \ No newline at end of file From 380289fd9e639927decef6686377db22fb31b614 Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:13:14 -0400 Subject: [PATCH 6/8] Restore sbt-scoverage 2.3.1 (now valid with Scala 2.13.16) --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 0c12ff5..7aef9a2 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ addSbtPlugin("io.spray" % "sbt-revolver" % "0.9.1") addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.3.1") -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.3") \ No newline at end of file +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.3.1") \ No newline at end of file From 2d440ef0226228988856c1d90186918f8b9990bb Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:14:52 -0400 Subject: [PATCH 7/8] Allow scala-xml version conflict (scoverage 2.x vs akka-http-xml) --- build.sbt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 91ea93c..fa608db 100644 --- a/build.sbt +++ b/build.sbt @@ -53,4 +53,5 @@ ThisBuild / assemblyMergeStrategy := { case "reference.conf" => MergeStrategy.concat case "META-INF/MANIFEST.MF" => MergeStrategy.discard case x => MergeStrategy.first -} \ No newline at end of file +} +ThisBuild / libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % "always" From e1aba02d9b238a6cb8106b7ded70b5402cb66330 Mon Sep 17 00:00:00 2001 From: Dominic Byrd-McDevitt Date: Thu, 7 May 2026 17:16:40 -0400 Subject: [PATCH 8/8] Update QueryBuilderTest assertions for cacheable date bounds --- .../api/v2/search/queryBuilders/QueryBuilderTest.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/scala/dpla/api/v2/search/queryBuilders/QueryBuilderTest.scala b/src/test/scala/dpla/api/v2/search/queryBuilders/QueryBuilderTest.scala index b8b29de..b0e2a94 100644 --- a/src/test/scala/dpla/api/v2/search/queryBuilders/QueryBuilderTest.scala +++ b/src/test/scala/dpla/api/v2/search/queryBuilders/QueryBuilderTest.scala @@ -635,7 +635,7 @@ class QueryBuilderTest extends AnyWordSpec with Matchers } "specify default filter gte" in { - val expected = Some("now-2000y") + val expected = Some("0001-01-01") val traversed = readString(dateFacetQuery, "aggs", "sourceResource.date.begin", "filter", "range", "sourceResource.date.begin", "gte") @@ -643,7 +643,7 @@ class QueryBuilderTest extends AnyWordSpec with Matchers } "specify year gte" in { - val expected = Some("now-2000y") + val expected = Some("0001-01-01") val params = minSearchParams .copy(facets = Some(Seq("sourceResource.date.end.year"))) val query = getJsSearchQuery(params) @@ -654,7 +654,7 @@ class QueryBuilderTest extends AnyWordSpec with Matchers } "specify month gte" in { - val expected = Some("now-416y") + val expected = Some("1600-01-01") val params = minSearchParams .copy(facets = Some(Seq("sourceResource.date.end.month"))) val query = getJsSearchQuery(params) @@ -665,7 +665,7 @@ class QueryBuilderTest extends AnyWordSpec with Matchers } "specify filter lte" in { - val expected = Some("now") + val expected = Some("now/d") val traversed = readString(dateFacetQuery, "aggs", "sourceResource.date.begin", "filter", "range", "sourceResource.date.begin", "lte") @@ -786,4 +786,4 @@ class QueryBuilderTest extends AnyWordSpec with Matchers assert(traversed == expected) } } -} +} \ No newline at end of file