Skip to content

Commit 10d3366

Browse files
roed314claude
andcommitted
Address review: project curves column only when displayed (LMFDB#6975)
The curves column is default-off but was added to the fixed db_cols projection, so every abvar/Fq search (and every download) fetched and deserialized the full curve arrays that the user never sees - up to ~2.2MB on the worst realistic browse page (g=2, q=167). Drop "curves" from the static db_cols and fetch it only when the column is actually shown: the search sets __projection__ to include curves when curves_requested(info) is true, and AbvarFq_download overrides a new Downloader.get_projection hook (a behavior-preserving extraction of the existing projection logic) to add curves only when it is in the download. Verified with the flask test client: default searches/downloads no longer project curves (worst page drops from 33 to 32 columns, saving 2.2MB), while showcol=curves still displays and downloads the equations; all 20 abvar tests plus number-field and ECNF download tests pass; pyflakes clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 0f78401 commit 10d3366

3 files changed

Lines changed: 36 additions & 7 deletions

File tree

lmfdb/abvar/fq/download.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,14 @@ def download_curves(self, label, lang='text'):
2929
lang=lang,
3030
title='Curves in abelian variety isogeny class %s,' % (label))
3131

32+
def get_projection(self, info, table, columns):
33+
proj = super().get_projection(info, table, columns)
34+
# The curves arrays are large, so only fetch them when the Curves column is
35+
# actually included in the download (see LMFDB#6975).
36+
if ("curves" in table.search_cols and "curves" not in proj
37+
and any(col.name == "curves" and col.default(info) for col in columns.columns)):
38+
proj = proj + ["curves"]
39+
return proj
40+
3241
def postprocess(self, rec, info, query):
3342
return AbvarFq_isoclass(rec)

lmfdb/abvar/fq/main.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,15 @@ def extended_code(c):
714714
ProcessedCol("number_fields", "av.fq.number_field", "Number fields", lambda nfs: ", ".join(nf_display_knowl(nf, field_pretty(nf)) for nf in nfs), default=False),
715715
SearchCol("galois_groups_pretty", "nf.galois_group", "Galois groups", download_col="galois_groups", default=False),
716716
SearchCol("decomposition_display_search", "av.decomposition", "Isogeny factors", download_col="decompositionraw")],
717-
db_cols=["label", "g", "q", "poly", "p_rank", "p_rank_deficit", "is_simple", "is_geometrically_simple", "simple_distinct", "simple_multiplicities", "is_primitive", "primitive_models", "curve_count", "curve_counts", "curves", "abvar_count", "abvar_counts", "jacobian_count", "hyp_count", "number_fields", "galois_groups", "slopes", "newton_elevation", "twist_count", "max_twist_degree", "geometric_extension_degree", "angle_rank", "angle_corank", "is_supersingular", "has_principal_polarization", "has_jacobian", "is_cyclic", "noncyclic_primes"])
717+
db_cols=["label", "g", "q", "poly", "p_rank", "p_rank_deficit", "is_simple", "is_geometrically_simple", "simple_distinct", "simple_multiplicities", "is_primitive", "primitive_models", "curve_count", "curve_counts", "abvar_count", "abvar_counts", "jacobian_count", "hyp_count", "number_fields", "galois_groups", "slopes", "newton_elevation", "twist_count", "max_twist_degree", "geometric_extension_degree", "angle_rank", "angle_corank", "is_supersingular", "has_principal_polarization", "has_jacobian", "is_cyclic", "noncyclic_primes"])
718+
719+
# The curves column holds potentially long lists of equations (up to ~6000 per row, and
720+
# 2+ MB per page of search results), so - unlike the other columns - it is left out of the
721+
# fixed db_cols projection above and only fetched from the database when the column is
722+
# actually displayed or included in a download. See LMFDB#6975.
723+
def curves_requested(info):
724+
"""Whether the (heavy, default-off) curves column is included in the current display/download."""
725+
return any(col.name == "curves" and col.default(info) for col in abvar_columns.columns)
718726

719727
def abvar_postprocess(res, info, query):
720728
gals = set()
@@ -742,6 +750,9 @@ def abvar_postprocess(res, info, query):
742750
)
743751
def abelian_variety_search(info, query):
744752
common_parse(info, query)
753+
if curves_requested(info):
754+
# Fetch the (heavy) curves arrays only when the Curves column is displayed (LMFDB#6975).
755+
query["__projection__"] = abvar_columns.db_cols + ["curves"]
745756

746757
@count_wrap(
747758
template="abvarfq-count-results.html",

lmfdb/utils/downloader.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,20 @@ def modify_query(self, info, query):
605605
"""
606606
pass
607607

608+
def get_projection(self, info, table, columns):
609+
"""
610+
This is a hook for downloaders to determine the database projection based on info.
611+
612+
By default it fetches the columns in ``columns.db_cols`` that are present in the
613+
search table. It is overridden when a heavy column should only be fetched when it
614+
is actually included in the download (see abelian varieties over Fq, LMFDB#6975).
615+
"""
616+
# It's fairly common to add virtual columns in postprocessing that are then used in MultiProcessedCols.
617+
# These virtual columns are often only used in display code and won't be present in the database, so we just strip them out
618+
if isinstance(columns.db_cols, list):
619+
return [col for col in columns.db_cols if col in table.search_cols]
620+
return columns.db_cols # some tables use 1 for project-to-all
621+
608622
def get_sort(self, info, query):
609623
"""
610624
This determines the sort order requested from the database.
@@ -705,12 +719,7 @@ def __call__(self, info):
705719

706720
# Determine which columns will be fetched from the database
707721
columns = info["columns"]
708-
# It's fairly common to add virtual columns in postprocessing that are then used in MultiProcessedCols.
709-
# These virtual columns are often only used in display code and won't be present in the database, so we just strip them out
710-
if isinstance(columns.db_cols, list):
711-
proj = [col for col in columns.db_cols if col in table.search_cols]
712-
else:
713-
proj = columns.db_cols # some tables use 1 for project-to-all
722+
proj = self.get_projection(info, table, columns)
714723

715724
# Extract the query and modify it
716725
try:

0 commit comments

Comments
 (0)