diff --git a/elastic/documents.py b/elastic/documents.py index 43d1577..d2f05c3 100644 --- a/elastic/documents.py +++ b/elastic/documents.py @@ -48,3 +48,12 @@ class GlobalDocument(Document): class Django: model = ElasticNews + + +@GLOBAL_INDEX.doc_type +class AnalyticsDocument(Document): + overview = fields.TextField() + updated_at = fields.DateField() + + class Django: + model = ElasticNews diff --git a/elastic/es_connect.py b/elastic/es_connect.py index c0b1f3d..8c4693c 100644 --- a/elastic/es_connect.py +++ b/elastic/es_connect.py @@ -5,7 +5,7 @@ Django版本的ES连接和操作模块 from elasticsearch import Elasticsearch from elasticsearch_dsl import connections import os -from .documents import AchievementDocument, UserDocument, GlobalDocument +from .documents import AchievementDocument, UserDocument, GlobalDocument, AnalyticsDocument from .indexes import ACHIEVEMENT_INDEX_NAME, USER_INDEX_NAME, GLOBAL_INDEX_NAME import hashlib import time @@ -46,10 +46,18 @@ def create_index_with_mapping(): # --- 3. 处理全局类型索引 --- if not es.indices.exists(index=GLOBAL_TYPES_INDEX_NAME): GlobalDocument.init() + AnalyticsDocument.init() default_types = ['软著', '专利', '奖状'] doc = GlobalDocument(type_list=default_types) doc.meta.id = 'types' doc.save() + try: + a = AnalyticsDocument() + a.meta.id = 'overview' + a.overview = json.dumps({}) + a.save() + except Exception: + pass print(f"✅ 创建索引 {GLOBAL_TYPES_INDEX_NAME} 并写入默认类型") else: try: @@ -60,6 +68,16 @@ def create_index_with_mapping(): doc.meta.id = 'types' doc.save() print("ℹ️ 全局类型文档缺失,已补充默认类型") + try: + AnalyticsDocument.get(id='overview') + except Exception: + try: + a = AnalyticsDocument() + a.meta.id = 'overview' + a.overview = json.dumps({}) + a.save() + except Exception: + pass # --- 4. 创建默认管理员用户(可选:也可检查用户是否已存在)--- # 这里简单处理:每次初始化都写入(可能重复),建议加唯一性判断 @@ -309,7 +327,29 @@ def search_by_any_field(keyword): print(f"模糊搜索失败: {str(e)}") return [] -ANALYTICS_CACHE = {"data": None, "ts": 0} +def _read_analytics_overview(): + try: + doc = AnalyticsDocument.get(id='overview') + payload = getattr(doc, 'overview', '') or '' + try: + return json.loads(payload) if payload else {} + except Exception: + return {} + except Exception: + return {} + +def _write_analytics_overview(data: dict): + try: + try: + doc = AnalyticsDocument.get(id='overview') + except Exception: + doc = AnalyticsDocument() + doc.meta.id = 'overview' + doc.overview = json.dumps(data, ensure_ascii=False) + doc.save() + return True + except Exception: + return False def _compute_hist(range_gte: str, interval: str, fmt: str): from elasticsearch_dsl import Search @@ -347,11 +387,16 @@ def compute_analytics(): } def get_analytics_overview(force: bool = False): - now_ts = time.time() - if force or ANALYTICS_CACHE["data"] is None or (now_ts - ANALYTICS_CACHE["ts"]) > 3600: - ANALYTICS_CACHE["data"] = compute_analytics() - ANALYTICS_CACHE["ts"] = now_ts - return ANALYTICS_CACHE["data"] + if force: + data = compute_analytics() + _write_analytics_overview(data) + return data + data = _read_analytics_overview() + if data: + return data + data = compute_analytics() + _write_analytics_overview(data) + return data def _seconds_until_hour(h: int): now = datetime.now() diff --git a/elastic/management/__init__.py b/elastic/management/__init__.py new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/elastic/management/__init__.py @@ -0,0 +1 @@ + diff --git a/elastic/management/commands/analyze_analytics.py b/elastic/management/commands/analyze_analytics.py new file mode 100644 index 0000000..01019bc --- /dev/null +++ b/elastic/management/commands/analyze_analytics.py @@ -0,0 +1,8 @@ +from django.core.management.base import BaseCommand +from elastic.es_connect import create_index_with_mapping, get_analytics_overview + +class Command(BaseCommand): + def handle(self, *args, **options): + create_index_with_mapping() + get_analytics_overview(force=True) + self.stdout.write("analytics updated") \ No newline at end of file