From 3525eb7b89f9673cb17f37a7b098c399c6249e17 Mon Sep 17 00:00:00 2001 From: Sean Whalen <44679+seanthegeek@users.noreply.github.com> Date: Fri, 24 Jul 2026 21:40:47 -0400 Subject: [PATCH] Correct the nested-mapping rationale in the create_indexes comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The comments claimed Kibana/OSD/Grafana "cannot terms-aggregate fields inside a nested mapping" — too absolute. Fact-checked empirically and against primary docs: Kibana/OSD visual editors (Lens and classic Visualize) do not support nested fields, but Vega panels can run nested aggregations (they just cannot render tables, per Elastic's docs), and Grafana >= 9.4 has a nested bucket aggregation (grafana/grafana#62301) but no reverse_nested, so parent-level metrics like Sum(message_count) return 0 inside per-signature buckets (reproduced live). Conclusion unchanged: the dynamic object mapping stays load-bearing for the shipped dashboards. PR #839's body was updated with the same correction. Co-Authored-By: Claude Fable 5 --- parsedmarc/elastic.py | 14 +++++++++----- parsedmarc/opensearch.py | 14 +++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/parsedmarc/elastic.py b/parsedmarc/elastic.py index 5c7ebfc0..304278a1 100644 --- a/parsedmarc/elastic.py +++ b/parsedmarc/elastic.py @@ -551,11 +551,15 @@ def create_indexes(names: list[str], settings: dict[str, Any] | None = None): for name in names: index = Index(name) try: - # Deliberately no Index.document() registration: Kibana/OpenSearch - # Dashboards/Grafana cannot terms-aggregate fields inside a - # `nested` mapping, so the dynamic `object` mapping produced by a - # bare create is load-bearing for the shipped dashboards. See - # issue #169 and the *_combined fields on _AggregateReportDoc. + # Deliberately no Index.document() registration: the shipped + # dashboards cannot rebuild their detail tables on a `nested` + # mapping — Kibana/OSD visual editors do not support nested + # fields, Vega can run nested aggregations but does not render + # tables, and Grafana's nested bucket aggregation (9.4+) lacks + # reverse_nested for parent-level metrics like message_count — + # so the dynamic `object` mapping produced by a bare create is + # load-bearing for the shipped dashboards. See issue #169 and + # the *_combined fields on _AggregateReportDoc. if not index.exists(): logger.debug("Creating Elasticsearch index: {0}".format(name)) if effective_settings: diff --git a/parsedmarc/opensearch.py b/parsedmarc/opensearch.py index e353c549..ede0c1b7 100644 --- a/parsedmarc/opensearch.py +++ b/parsedmarc/opensearch.py @@ -469,11 +469,15 @@ def create_indexes(names: list[str], settings: dict[str, Any] | None = None): for name in names: index = Index(name) try: - # Deliberately no Index.document() registration: Kibana/OpenSearch - # Dashboards/Grafana cannot terms-aggregate fields inside a - # `nested` mapping, so the dynamic `object` mapping produced by a - # bare create is load-bearing for the shipped dashboards. See - # issue #169 and the *_combined fields on _AggregateReportDoc. + # Deliberately no Index.document() registration: the shipped + # dashboards cannot rebuild their detail tables on a `nested` + # mapping — Kibana/OSD visual editors do not support nested + # fields, Vega can run nested aggregations but does not render + # tables, and Grafana's nested bucket aggregation (9.4+) lacks + # reverse_nested for parent-level metrics like message_count — + # so the dynamic `object` mapping produced by a bare create is + # load-bearing for the shipped dashboards. See issue #169 and + # the *_combined fields on _AggregateReportDoc. if not index.exists(): logger.debug("Creating OpenSearch index: {0}".format(name)) if settings is None: