"""育种统计 数据模型(一期 2 个最基础:ABLUP·EBV + 配合力 GCA/SCA)""" from datetime import datetime from sqlalchemy import ( JSON, Boolean, Date, DateTime, Float, ForeignKey, Index, Integer, Numeric, String, Text, ) from sqlalchemy.orm import Mapped, mapped_column from app.core.base_model import MappedBase, ModelMixin, UserMixin class PredictionModel(ModelMixin, UserMixin, MappedBase): """育种值模型/批次元数据(§3.12)。""" __tablename__ = "bre_prediction" model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="模型名称") trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) method: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="方法(ABLUP/COMBINING)") stage: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="测定阶段(juvenile幼龄/evaluation成株)") accuracy: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="模型精度(批次PA=√均值可靠性)") train_n: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="训练样本量") heritability: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="遗传力 h²") predict_date: Mapped[datetime | None] = mapped_column(Date, nullable=True, comment="预测日期") data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本(输入快照版本)") input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256(表型+系谱)") engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本") is_active: Mapped[bool | None] = mapped_column(Boolean, nullable=True, default=False, comment="当前生效版本(同性状最近批次,供版本回滚)") note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_prediction_created_deleted", "created_time", "is_deleted"), ) class PredictionValueModel(ModelMixin, UserMixin, MappedBase): """个体预测值(EBV 持久化,V1.1 建表)。""" __tablename__ = "bre_prediction_value" prediction_id: Mapped[int] = mapped_column( Integer, ForeignKey("bre_prediction.id", ondelete="CASCADE"), index=True, nullable=False, comment="关联模型" ) germplasm_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_germplasm.id", ondelete="CASCADE"), index=True, nullable=True, comment="种质(亲本级)" ) tree_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_tree.id", ondelete="CASCADE"), index=True, nullable=True, comment="单株(树级)" ) trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) predicted_value: Mapped[float | None] = mapped_column(Float, nullable=True, comment="预测值/EBV") reliability: Mapped[float | None] = mapped_column(Float, nullable=True, comment="可靠性") pa: Mapped[float | None] = mapped_column(Float, nullable=True, comment="预测准确度 PA=√可靠性") rank: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="排名") __table_args__ = ( Index("ix_bre_prediction_value_created_deleted", "created_time", "is_deleted"), ) class CombiningAbilityModel(ModelMixin, UserMixin, MappedBase): """配合力分析结果(§3.12;GCA 按亲本、SCA 按组合)。""" __tablename__ = "bre_combining_ability" model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="模型名称") trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方法") design_type: Mapped[str | None] = mapped_column( String(32), nullable=True, comment="分析采用交配设计(full_diallel/partial_diallel/line_tester/nciii,结果快照)", ) gca_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="亲本一般配合力 {parent: gca}") sca_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="组合特殊配合力 {combo: {p1,p2,sca}}") anova_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="配合力方差分解(F_gca/p_gca)") __table_args__ = ( Index("ix_bre_combining_ability_created_deleted", "created_time", "is_deleted"), ) class SelectionIndexModel(ModelMixin, UserMixin, MappedBase): """选择指数 批次(加权 Z 综合;可选接入 ABLUP 批次 EBV 与 h² 加权,结果持久化)。""" __tablename__ = "bre_selection_index" model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="批次名称") method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="SI_EBV/SI_PHENO") weights_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: 用户权重}") batch_refs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: ABLUP批次id}") heritability_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: h²}") top_n: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="返回前 N") result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{traits, top:[{tree_id,index,detail}]}") __table_args__ = ( Index("ix_bre_selection_index_created_deleted", "created_time", "is_deleted"), ) class AnovaResultModel(ModelMixin, UserMixin, MappedBase): """单因素 ANOVA 结果(家系方差组分 + 广义遗传力 H²)。""" __tablename__ = "bre_anova_result" model_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="批次名称") trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="ANOVA/H2") result_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="方差组分/H²/F/p") __table_args__ = ( Index("ix_bre_anova_result_created_deleted", "created_time", "is_deleted"), ) class CvResultModel(ModelMixin, UserMixin, MappedBase): """k-fold 交叉验证结果(外部验证预测准确度,区别于 PEV 可靠性)。""" __tablename__ = "bre_cv_result" trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码") method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="KFCV/ABLUP 或 KFCV/GXE") k: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="折数") n_total: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="总记录数") n_individuals: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="加性个体数") mean_pearson: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="有效折预测-观测 pearson 均值") mean_rmse: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="有效折 RMSE 均值") pooled_pearson: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="合并全部折 pearson") pooled_rmse: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="合并全部折 RMSE") cv_accuracy: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="预测准确度(=mean_pearson)") h2: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="有效折遗传力均值") folds_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="折明细快照") data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本") input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256") engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本") note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_cv_result_created_deleted", "created_time", "is_deleted"), ) class CvFoldModel(ModelMixin, UserMixin, MappedBase): """k-fold CV 折明细。""" __tablename__ = "bre_cv_fold" cv_result_id: Mapped[int] = mapped_column( Integer, ForeignKey("bre_cv_result.id", ondelete="CASCADE"), index=True, nullable=False, comment="关联 CV 结果" ) fold_idx: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="折号(1-based)") n_train: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="训练记录数") n_test: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="测试个体数") n_eval: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="有效评估个体数") pearson: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="折内预测-观测 pearson") rmse: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="折内 RMSE") error: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="折失败原因") __table_args__ = ( Index("ix_bre_cv_fold_created_deleted", "created_time", "is_deleted"), ) class StatisticsJobModel(ModelMixin, UserMixin, MappedBase): """统计异步任务(R 引擎;ABLUP/COMBINING 提交后异步执行并回写结果)。""" __tablename__ = "bre_statistics_job" job_type: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="ABLUP/COMBINING") params_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="入参") status: Mapped[str] = mapped_column(String(16), nullable=False, default="PENDING", comment="PENDING/RUNNING/SUCCESS/FAILED") result_ref: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="结果主表 id") error_msg: Mapped[str | None] = mapped_column(Text, nullable=True, comment="错误信息") started_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) finished_time: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) __table_args__ = ( Index("ix_bre_statistics_job_created_deleted", "created_time", "is_deleted"), ) class GeneticCorrResultModel(ModelMixin, UserMixin, MappedBase): """成对双性状 BLUP 遗传相关矩阵结果(MT-BLUP,§8.18)。 逐对 bivariate 估计 σ²a1/σ²a2/σ²a12(固定单性状方差、仅对遗传相关 ρ 作 1-D 剖面 REML golden-max),输出遗传相关矩阵 r_g 供 Smith-Hazel 指数 G 矩阵非对角替换 Calo 近似。 """ __tablename__ = "bre_genetic_corr_result" trait_ids_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{trait_code: trait_id}") matrix_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="遗传相关矩阵 {code: {code: r_g}}") sigma_a_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="加性方差矩阵 {code: {code: σa}}") heritability_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{code: h²}") pairs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="逐对详情 {pair: {r_g, va1, va2, ve1, ve2, n_common, converged, warning}}") n_common: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="成对共有树数(最小)") data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本") input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256(表型+系谱)") engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本") note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_genetic_corr_result_created_deleted", "created_time", "is_deleted"), ) class TypeBResultModel(ModelMixin, UserMixin, MappedBase): """Type-B 多环境遗传相关结果(§8.27)。 同一性状在多个环境(site=研究点 / year=年份)的表型,以环境互为"性状"逐对 REML 双性状 BLUP 估计遗传相关 r_g(复用 mtblup.solve_bivariate);r_g 均值 即 Type-B 遗传相关,衡量基因型×环境互作强度与跨环境遗传稳定性。 """ __tablename__ = "bre_type_b_result" trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码") env_dim: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="环境维度(site/year)") method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方法(reml/calo,calo 无环境级EBV时回退reml)") envs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="{env_code: env_label}") matrix_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="环境间遗传相关矩阵 {env: {env: r_g}}") pairs_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="逐对详情 {pair: {r_g, va1, va2, ve1, ve2, n_common, converged, warning}}") n_common: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="成对共有树数(最小)") data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本") input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256") engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本") note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_type_b_result_created_deleted", "created_time", "is_deleted"), ) class StabilityResultModel(ModelMixin, UserMixin, MappedBase): """AMMI / Finlay-Wilkinson 稳定性分析结果(§8.18)。 两因素(基因型×环境)均值表 → AMMI SVD(IPC1/IPC2/ASV/ecovalence) 与 Finlay-Wilkinson 回归斜率 b,输出稳定性排名。 """ __tablename__ = "bre_stability_result" trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码") env_dim: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="环境维度(site/year)") methods: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="方法(ammi,finlay)") detail_json: Mapped[dict | None] = mapped_column(JSON, nullable=True, comment="稳定性分析明细快照") data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本") input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256") engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本") note: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_stability_result_created_deleted", "created_time", "is_deleted"), ) class GwasResultModel(ModelMixin, UserMixin, MappedBase): """GWAS 关联分析批次结果(§8.22)。 GLM+PC 逐标记单标记回归(纯 numpy + fdist),输出显著标记集与 QTL 区间。 """ __tablename__ = "bre_gwas_result" dataset_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_genotyping_dataset.id", ondelete="CASCADE"), index=True, nullable=True, comment="基因型数据集" ) trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) trait_code: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="性状编码") method: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="方法(gwas/ssgwas)") n_individuals: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="样本数(表型∩基因型)") n_markers: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="标记总数") m_after_maf: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="MAF 过滤后标记数") maf_min: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="MAF 过滤下限") n_pc: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="群体结构主成分数") sig_level: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="显著性水平") threshold_bonf: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="Bonferroni 阈值") n_sig_bonf: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="Bonferroni 显著标记数") n_sig_fdr: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="FDR q<α 标记数") n_qtl: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="QTL 区间数") data_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="数据版本") input_hash: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="输入快照SHA256(表型+系谱+基因型)") engine_version: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="统计引擎版本") remark: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_gwas_result_created_deleted", "created_time", "is_deleted"), ) class GwasSnpModel(ModelMixin, UserMixin, MappedBase): """GWAS 逐标记关联结果(§8.22)。""" __tablename__ = "bre_gwas_snp" gwas_result_id: Mapped[int] = mapped_column( Integer, ForeignKey("bre_gwas_result.id", ondelete="CASCADE"), index=True, nullable=False, comment="关联 GWAS 批次" ) marker_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_marker.id", ondelete="SET NULL"), index=True, nullable=True, comment="标记" ) marker_name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="标记名称") chromosome: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="染色体") position: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="物理位置(bp)") maf: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="次要等位频率") effect: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="加性效应") se: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="效应标准误") t_value: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="t 值") p_value: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="p 值") neg_log10p: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="−log10(p)") q_value: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="BH-FDR q 值") sig_bonf: Mapped[bool | None] = mapped_column(Boolean, nullable=True, comment="Bonferroni 显著") sig_fdr: Mapped[bool | None] = mapped_column(Boolean, nullable=True, comment="FDR 显著") __table_args__ = ( Index("ix_bre_gwas_snp_created_deleted", "created_time", "is_deleted"), ) class QtlModel(ModelMixin, UserMixin, MappedBase): """QTL 区间(§8.22)。 source=known 为人工录入已知 QTL(桃成熟期/果重等位点);source=gwas 为 GWAS 显著标记聚类自动定位(gwas_result_id 关联批次)。 """ __tablename__ = "bre_qtl" trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="性状" ) chromosome: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="染色体") start_bp: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="区间起点(bp)") end_bp: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="区间终点(bp)") peak_marker_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_marker.id", ondelete="SET NULL"), index=True, nullable=True, comment="峰标记" ) peak_marker_name: Mapped[str | None] = mapped_column(String(64), nullable=True, comment="峰标记名称") peak_p: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="峰标记 p 值") n_markers: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="区间显著标记数") effect: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="区间峰效应") source: Mapped[str | None] = mapped_column(String(8), nullable=True, default="known", comment="来源(known/gwas)") gwas_result_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_gwas_result.id", ondelete="CASCADE"), index=True, nullable=True, comment="来源 GWAS 批次(source=gwas 时)" ) remark: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_qtl_created_deleted", "created_time", "is_deleted"), ) class MasPanelModel(ModelMixin, UserMixin, MappedBase): """MAS 标记辅助选择面板(§8.22)。 一组与目标性状关联的标记(QTL 峰标记),供决策预览按有利剂量命中童期幼苗。 """ __tablename__ = "bre_mas_panel" panel_name: Mapped[str | None] = mapped_column(String(128), nullable=True, comment="面板名称") trait_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_trait.id", ondelete="CASCADE"), index=True, nullable=True, comment="目标性状" ) n_markers: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="标记数") remark: Mapped[str | None] = mapped_column(String(512), nullable=True, comment="备注") __table_args__ = ( Index("ix_bre_mas_panel_created_deleted", "created_time", "is_deleted"), ) class MasPanelMarkerModel(ModelMixin, UserMixin, MappedBase): """MAS 面板标记(§8.22)。""" __tablename__ = "bre_mas_panel_marker" panel_id: Mapped[int] = mapped_column( Integer, ForeignKey("bre_mas_panel.id", ondelete="CASCADE"), index=True, nullable=False, comment="关联面板" ) marker_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("bre_marker.id", ondelete="SET NULL"), index=True, nullable=True, comment="标记" ) favorable_dose: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="有利剂量(0/1/2)") effect: Mapped[float | None] = mapped_column(Numeric, nullable=True, comment="效应(绝对值参考)") direction: Mapped[str | None] = mapped_column(String(8), nullable=True, default="high", comment="方向(high=剂量≥favorable_dose命中 / low=剂量≤命中)") mode: Mapped[str | None] = mapped_column( String(16), nullable=True, default="additive", comment="基因作用模式:additive加性(剂量≥fav)/dominance显性(剂量≥1高/≤1低)/recessive隐性(剂量=2高/0低)/allele等位存在(有利等位)/haplotype单倍型(同组全命中)") favorable_allele: Mapped[str | None] = mapped_column(String(16), nullable=True, comment="有利等位(allele/haplotype 模式用,SSR 等位索引)") haplotype_group: Mapped[str | None] = mapped_column(String(32), nullable=True, comment="单倍型组(haplotype 模式:同组标记全命中才计 1)") __table_args__ = ( Index("ix_bre_mas_panel_marker_created_deleted", "created_time", "is_deleted"), )