Repository navigation
feat(fts): record scorer_build_ms for the exec-local BM25 scorer fallback #7807
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,7 @@ use datafusion::error::{DataFusionError, Result as DataFusionResult}; | |
| use datafusion::execution::SendableRecordBatchStream; | ||
| use datafusion::physical_plan::empty::EmptyExec; | ||
| use datafusion::physical_plan::execution_plan::{Boundedness, EmissionType}; | ||
| use datafusion::physical_plan::metrics::{ExecutionPlanMetricsSet, MetricsSet}; | ||
| use datafusion::physical_plan::metrics::{ExecutionPlanMetricsSet, Gauge, MetricsSet}; | ||
| use datafusion::physical_plan::repartition::RepartitionExec; | ||
| use datafusion::physical_plan::stream::RecordBatchStreamAdapter; | ||
| use datafusion::physical_plan::union::UnionExec; | ||
|
|
@@ -166,6 +166,9 @@ pub struct FtsIndexMetrics { | |
| and_candidates_pruned_before_return: Count, | ||
| and_full_scores: Count, | ||
| freqs_collected: Count, | ||
| /// Wall time (ms) of the exec-local `build_global_bm25_scorer` | ||
| /// fallback; zero when a preset base scorer was injected. | ||
| scorer_build_ms: Gauge, | ||
| baseline_metrics: BaselineMetrics, | ||
| } | ||
|
|
||
|
|
@@ -179,13 +182,18 @@ impl FtsIndexMetrics { | |
| .new_count(AND_CANDIDATES_PRUNED_BEFORE_RETURN_METRIC, partition), | ||
| and_full_scores: metrics.new_count(AND_FULL_SCORES_METRIC, partition), | ||
| freqs_collected: metrics.new_count(FREQS_COLLECTED_METRIC, partition), | ||
| scorer_build_ms: metrics.new_gauge("scorer_build_ms", partition), | ||
| baseline_metrics: BaselineMetrics::new(metrics, partition), | ||
| } | ||
| } | ||
|
|
||
| pub fn record_parts_searched(&self, num_parts: usize) { | ||
| self.partitions_searched.add(num_parts); | ||
| } | ||
|
|
||
| pub fn record_scorer_build(&self, elapsed: std::time::Duration) { | ||
| self.scorer_build_ms.set(elapsed.as_millis() as usize); | ||
| } | ||
|
Comment on lines
+194
to
+196
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π Maintainability & Code Quality | π Major | β‘ Quick win Document the new public metric API.
As per coding guidelines, document all public APIs with examples and links to relevant structs and methods. π€ Prompt for AI AgentsSource: Coding guidelines |
||
| } | ||
|
|
||
| impl MetricsCollector for FtsIndexMetrics { | ||
|
|
@@ -521,11 +529,16 @@ impl ExecutionPlan for MatchQueryExec { | |
| let tokens = collect_query_tokens(&query.terms, &mut tokenizer); | ||
| let base_scorer = match preset_base_scorer { | ||
| Some(scorer) => scorer, | ||
| None => Arc::new( | ||
| build_global_bm25_scorer(&indices, &tokens, ¶ms) | ||
| .boxed() | ||
| .await?, | ||
| ), | ||
| None => { | ||
| let scorer_start = std::time::Instant::now(); | ||
| let scorer = Arc::new( | ||
| build_global_bm25_scorer(&indices, &tokens, ¶ms) | ||
| .boxed() | ||
| .await?, | ||
| ); | ||
| metrics.record_scorer_build(scorer_start.elapsed()); | ||
| scorer | ||
| } | ||
|
Comment on lines
+532
to
+541
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π Maintainability & Code Quality | π Major | ποΈ Heavy lift π§© Analysis chainπ Script executed: #!/bin/bash
set -euo pipefail
# Inspect relevant portions of the file and nearby tests/usage.
git ls-files rust/lance/src/io/exec/fts.rs rust/lance/src | sed -n '1,20p'
echo "--- outline fts.rs ---"
ast-grep outline rust/lance/src/io/exec/fts.rs --view expanded || true
echo "--- snippets around target lines ---"
sed -n '500,560p' rust/lance/src/io/exec/fts.rs
echo "--- more snippets around other cited lines ---"
sed -n '1060,1120p' rust/lance/src/io/exec/fts.rs
echo "--- and around third cited lines ---"
sed -n '1360,1425p' rust/lance/src/io/exec/fts.rs
echo "--- tests / scorer metrics references ---"
rg -n "record_scorer_build|build_global_bm25_scorer|FlatMatchQueryExec|scorer" rust/lance/src/io/exec/fts.rs rust/lance/tests rust/lance/src -g '!target' -g '!dist' || trueRepository: lance-format/lance Length of output: 42474 π Script executed: #!/bin/bash
set -euo pipefail
sed -n '2320,2485p' rust/lance/src/io/exec/fts.rs
echo "---"
sed -n '2485,2635p' rust/lance/src/io/exec/fts.rs
echo "--- search for no-segment / fallback coverage ---"
rg -n "no segments|without segments|preset scorer|base_scorer|with_base_scorer|build_scorer|FlatMatchQueryExec::new|FlatMatchQueryExec::new_with_segments|MatchQueryExec::new_with_segments" rust/lance/src/io/exec/fts.rsRepository: lance-format/lance Length of output: 15785 π Script executed: #!/bin/bash
set -euo pipefail
sed -n '2170,2355p' rust/lance/src/io/exec/fts.rs
echo "---"
rg -n "scorer_build_ms|record_scorer_build|ExecutionPlanMetricsSet|baseline_metrics" rust/lance/src/io/exec/fts.rsRepository: lance-format/lance Length of output: 10241 π Script executed: #!/bin/bash
set -euo pipefail
rg -n "FlatMatchQueryExec|PhraseQueryExec|with_base_scorer|scorer_build_ms|no segments|preset scorer|base_scorer" rust/lance/src/io/exec/fts.rsRepository: lance-format/lance Length of output: 4158 Centralize scorer timing and add coverage for the override paths.
π€ Prompt for AI AgentsSource: Coding guidelines |
||
| }; | ||
|
|
||
| pre_filter.wait_for_ready().await?; | ||
|
|
@@ -1066,13 +1079,16 @@ impl ExecutionPlan for FlatMatchQueryExec { | |
| Some(scorer) => (*scorer).clone(), | ||
| None => { | ||
| let query_tokens = collect_query_tokens(&query.terms, &mut tokenizer); | ||
| build_global_bm25_scorer( | ||
| let scorer_start = std::time::Instant::now(); | ||
| let scorer = build_global_bm25_scorer( | ||
| &indices, | ||
| &query_tokens, | ||
| &FtsSearchParams::new(), | ||
| ) | ||
| .boxed() | ||
| .await? | ||
| .await?; | ||
| metrics.record_scorer_build(scorer_start.elapsed()); | ||
| scorer | ||
| } | ||
| }; | ||
| (tokenizer, Some(base_scorer)) | ||
|
|
@@ -1379,11 +1395,16 @@ impl ExecutionPlan for PhraseQueryExec { | |
| let tokens = collect_query_tokens(&query.terms, &mut tokenizer); | ||
| let base_scorer = match preset_base_scorer { | ||
| Some(scorer) => scorer, | ||
| None => Arc::new( | ||
| build_global_bm25_scorer(&indices, &tokens, ¶ms) | ||
| .boxed() | ||
| .await?, | ||
| ), | ||
| None => { | ||
| let scorer_start = std::time::Instant::now(); | ||
| let scorer = Arc::new( | ||
| build_global_bm25_scorer(&indices, &tokens, ¶ms) | ||
| .boxed() | ||
| .await?, | ||
| ); | ||
| metrics.record_scorer_build(scorer_start.elapsed()); | ||
| scorer | ||
| } | ||
| }; | ||
|
|
||
| pre_filter.wait_for_ready().await?; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π― Functional Correctness | π‘ Minor | β‘ Quick win
π§© Analysis chain
π Script executed:
Repository: lance-format/lance
Length of output: 8368
π Web query:
DataFusion MetricBuilder with_category MetricCategory::Timing new_gauge uncategorized EXPLAIN ANALYZE timing filter Gauge custom metricπ‘ Result:
In Apache DataFusion, the MetricBuilder is used to construct metrics, such as counters, gauges, and timers, within execution plans [1][2]. When creating a metric, you can assign it a semantic category using the.with_category method, which accepts a MetricCategory enum [3][4]. The MetricCategory enum classifies metrics to allow for selective filtering during EXPLAIN ANALYZE output [4][5]. The available categories are: Rows: Metrics tracking row counts [4]. Bytes: Metrics tracking data volume [4]. Timing: Metrics measuring wall-clock time, such as elapsed_compute [4]. Uncategorized: The default category for custom Count or Gauge metrics that are not explicitly assigned a specific category [4][5]. When implementing a custom gauge, you can use MetricBuilder to initialize it and assign it a category [3][6]. For example, if you wanted to explicitly categorize a custom timing metric, you would use MetricCategory::Timing [4]. If no category is specified during construction, the metric defaults to Uncategorized [4][5]. The EXPLAIN ANALYZE command uses these categories to filter which metrics are displayed in the query plan output [4][7]. Users can control this via configuration (e.g., setting datafusion.explain.analyze_categories), which determines whether metrics assigned to categories like Timing or Uncategorized are shown [4][5]. This is particularly useful for excluding non-deterministic timing metrics in regression tests [4][5]. Example usage pattern: MetricBuilder::new(&metrics).gauge("my_custom_metric", partition).with_category(MetricCategory::Timing) // Categorizing as Timing.build;
Citations:
π Script executed:
Repository: lance-format/lance
Length of output: 250
π Script executed:
Repository: lance-format/lance
Length of output: 6115
Classify
scorer_build_msas timing.new_gauge("scorer_build_ms", partition)leaves this wall-time metric uncategorized, so timing-filteredEXPLAIN ANALYZEoutput can omit it. UseMetricBuilderwithMetricCategory::Timing.π€ Prompt for AI Agents