This is an automated email from the ASF dual-hosted git repository.
abhishekrb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 96bd4ebf70b Add optional realtimeSegmentsOnly in query context (#18329)
96bd4ebf70b is described below
commit 96bd4ebf70b9cbac81efc96ce653b63bdced6888
Author: aho135 <[email protected]>
AuthorDate: Thu Aug 28 07:16:07 2025 -0700
Add optional realtimeSegmentsOnly in query context (#18329)
Adds an optional query context called realtimeSegmentsOnly that when set to
true will only return results from realtime segments.
---------
Co-authored-by: Andrew Ho <[email protected]>
---
docs/querying/query-context-reference.md | 1 +
.../java/org/apache/druid/query/QueryContext.java | 5 +++
.../java/org/apache/druid/query/QueryContexts.java | 3 ++
.../org/apache/druid/query/QueryContextTest.java | 11 +++++
.../druid/client/CachingClusteredClient.java | 4 ++
.../druid/client/CachingClusteredClientTest.java | 50 ++++++++++++++++++++++
.../query-context-completions.ts | 4 ++
7 files changed, 78 insertions(+)
diff --git a/docs/querying/query-context-reference.md
b/docs/querying/query-context-reference.md
index acc762fa9fe..52515236620 100644
--- a/docs/querying/query-context-reference.md
+++ b/docs/querying/query-context-reference.md
@@ -70,6 +70,7 @@ Unless otherwise noted, the following parameters apply to all
query types, and t
|`setProcessingThreadNames`|`true`| Whether processing thread names will be
set to `queryType_dataSource_intervals` while processing a query. This aids in
interpreting thread dumps, and is on by default. Query overhead can be reduced
slightly by setting this to `false`. This has a tiny effect in most scenarios,
but can be meaningful in high-QPS, low-per-segment-processing-time scenarios. |
|`sqlPlannerBloat`|`1000`|Calcite parameter which controls whether to merge
two Project operators when inlining expressions causes complexity to increase.
Implemented as a workaround to exception `There are not enough rules to produce
a node with desired properties: convention=DRUID, sort=[]` thrown after
rejecting the merge of two projects.|
|`cloneQueryMode`|`excludeClones`| Indicates whether clone Historicals should
be queried by brokers. Clone servers are created by the `cloneServers`
Coordinator dynamic configuration. Possible values are `excludeClones`,
`includeClones` and `preferClones`. `excludeClones` means that clone
Historicals are not queried by the broker. `preferClones` indicates that when
given a choice between the clone Historical and the original Historical which
is being cloned, the broker chooses the clones [...]
+|`realtimeSegmentsOnly` |`false`| When set to true, only query realtime
segments. Historical segments are excluded. |
## Parameters by query type
diff --git a/processing/src/main/java/org/apache/druid/query/QueryContext.java
b/processing/src/main/java/org/apache/druid/query/QueryContext.java
index b90be50e89a..096fd4afe9b 100644
--- a/processing/src/main/java/org/apache/druid/query/QueryContext.java
+++ b/processing/src/main/java/org/apache/druid/query/QueryContext.java
@@ -747,4 +747,9 @@ public class QueryContext
{
return getBoolean(QueryContexts.CTX_PREPLANNED,
QueryContexts.DEFAULT_PREPLANNED);
}
+
+ public boolean isRealtimeSegmentsOnly()
+ {
+ return getBoolean(QueryContexts.REALTIME_SEGMENTS_ONLY,
QueryContexts.DEFAULT_REALTIME_SEGMENTS_ONLY);
+ }
}
diff --git a/processing/src/main/java/org/apache/druid/query/QueryContexts.java
b/processing/src/main/java/org/apache/druid/query/QueryContexts.java
index d288775977c..0619e521b7a 100644
--- a/processing/src/main/java/org/apache/druid/query/QueryContexts.java
+++ b/processing/src/main/java/org/apache/druid/query/QueryContexts.java
@@ -137,6 +137,9 @@ public class QueryContexts
public static final String NATIVE_QUERY_SQL_PLANNING_MODE_COUPLED =
"COUPLED";
public static final String NATIVE_QUERY_SQL_PLANNING_MODE_DECOUPLED =
"DECOUPLED";
+ public static final String REALTIME_SEGMENTS_ONLY = "realtimeSegmentsOnly";
+ public static final boolean DEFAULT_REALTIME_SEGMENTS_ONLY = false;
+
public static final String CTX_PREPLANNED = "prePlanned";
public static final boolean DEFAULT_PREPLANNED = true;
diff --git
a/processing/src/test/java/org/apache/druid/query/QueryContextTest.java
b/processing/src/test/java/org/apache/druid/query/QueryContextTest.java
index 277713abe33..0cb931e50d2 100644
--- a/processing/src/test/java/org/apache/druid/query/QueryContextTest.java
+++ b/processing/src/test/java/org/apache/druid/query/QueryContextTest.java
@@ -429,6 +429,17 @@ public class QueryContextTest
assertNotNull(timeseries.getContext());
}
+ @Test
+ public void testIsRealtimeSegmentsOnly()
+ {
+ assertFalse(QueryContext.empty().isRealtimeSegmentsOnly());
+ assertTrue(
+ QueryContext
+ .of(ImmutableMap.of(QueryContexts.REALTIME_SEGMENTS_ONLY, true))
+ .isRealtimeSegmentsOnly()
+ );
+ }
+
@Test
public void testSerialization() throws Exception
{
diff --git
a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java
b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java
index e0c7f0e4e5f..33237f372a2 100644
--- a/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java
+++ b/server/src/main/java/org/apache/druid/client/CachingClusteredClient.java
@@ -457,6 +457,7 @@ public class CachingClusteredClient implements
QuerySegmentWalker
filterFieldsForPruning = null;
}
+ boolean isRealtimeSegmentOnly = query.context().isRealtimeSegmentsOnly();
// Filter unneeded chunks based on partition dimension
for (TimelineObjectHolder<String, ServerSelector> holder :
serversLookup) {
final Set<PartitionChunk<ServerSelector>> filteredChunks;
@@ -473,6 +474,9 @@ public class CachingClusteredClient implements
QuerySegmentWalker
}
for (PartitionChunk<ServerSelector> chunk : filteredChunks) {
ServerSelector server = chunk.getObject();
+ if (isRealtimeSegmentOnly && !server.isRealtimeSegment()) {
+ continue; // Skip historical segments when only realtime segments
are requested
+ }
final SegmentDescriptor segment = new SegmentDescriptor(
holder.getInterval(),
holder.getVersion(),
diff --git
a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java
b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java
index 1318a7c344a..621bbf0a044 100644
---
a/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java
+++
b/server/src/test/java/org/apache/druid/client/CachingClusteredClientTest.java
@@ -3099,6 +3099,56 @@ public class CachingClusteredClientTest
Assert.assertNotEquals(etag1, etag2);
}
+ @Test
+ public void testRealtimeSegmentsQueryContext()
+ {
+ final Interval interval = Intervals.of("2016-01-01/2016-01-02");
+ final Interval queryInterval =
Intervals.of("2016-01-01T14:00:00/2016-01-02T14:00:00");
+ final DataSegment dataSegment = new DataSegment(
+ "dataSource",
+ interval,
+ "ver",
+ ImmutableMap.of(
+ "type", "hdfs",
+ "path", "/tmp"
+ ),
+ ImmutableList.of("product"),
+ ImmutableList.of("visited_sum"),
+ NoneShardSpec.instance(),
+ 9,
+ 12334
+ );
+ final ServerSelector selector = new ServerSelector(
+ dataSegment,
+ new HighestPriorityTierSelectorStrategy(new
RandomServerSelectorStrategy()),
+ HistoricalFilter.IDENTITY_FILTER
+ );
+ selector.addServerAndUpdateSegment(new QueryableDruidServer(servers[0],
null), dataSegment);
+ timeline.add(interval, "ver", new SingleElementPartitionChunk<>(selector));
+
+ final TimeBoundaryQuery query = Druids.newTimeBoundaryQueryBuilder()
+ .dataSource(DATA_SOURCE)
+ .intervals(new
MultipleIntervalSegmentSpec(ImmutableList.of(queryInterval)))
+ .context(ImmutableMap.of("realtimeSegmentsOnly", false))
+ .randomQueryId()
+ .build();
+
+ final TimeBoundaryQuery query2 = Druids.newTimeBoundaryQueryBuilder()
+ .dataSource(DATA_SOURCE)
+ .intervals(new
MultipleIntervalSegmentSpec(ImmutableList.of(queryInterval)))
+ .context(ImmutableMap.of("realtimeSegmentsOnly", true))
+ .randomQueryId()
+ .build();
+
+ final ResponseContext responseContext = initializeResponseContext();
+
+ getDefaultQueryRunner().run(QueryPlus.wrap(query), responseContext);
+ getDefaultQueryRunner().run(QueryPlus.wrap(query2), responseContext);
+ final Map<String, Integer> remainingResponseMap = (Map<String, Integer>)
responseContext.get(ResponseContext.Keys.REMAINING_RESPONSES_FROM_QUERY_SERVERS);
+ Assert.assertEquals(1, remainingResponseMap.get(query.getId()).intValue());
+ Assert.assertEquals(0,
remainingResponseMap.get(query2.getId()).intValue());
+ }
+
@SuppressWarnings("unchecked")
private QueryRunner getDefaultQueryRunner()
{
diff --git
a/web-console/src/dialogs/edit-context-dialog/query-context-completions.ts
b/web-console/src/dialogs/edit-context-dialog/query-context-completions.ts
index 0b7abe19e7c..e74513c7e28 100644
--- a/web-console/src/dialogs/edit-context-dialog/query-context-completions.ts
+++ b/web-console/src/dialogs/edit-context-dialog/query-context-completions.ts
@@ -72,6 +72,10 @@ export const QUERY_CONTEXT_COMPLETIONS: JsonCompletionRule[]
= [
value: 'vectorize',
documentation: 'Enable vectorized query execution',
},
+ {
+ value: 'realtimeSegmentsOnly',
+ documentation: 'Whether to query only realtime segments',
+ },
{
value: 'vectorSize',
documentation: 'Vector size for vectorized execution',
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]