删除以前版本文件

This commit is contained in:
2025-08-02 16:55:33 +08:00
parent d55dd75ff8
commit 6558541a6f
4 changed files with 182 additions and 140 deletions

View File

@@ -55,11 +55,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- 生产环境单表 + 测试环境分表
- 生产环境单表 + 测试环境单表
**示例代码**
- `demo/Query.py`: 独立的Cassandra查询比对脚本示例
- `demo/twcsQuery.py`: 另一个查询示例
- `demo/CalculationLibrary.py`: 分表计算逻辑参考实现
- `test_sharding.py`: 分表功能测试脚本
**核心文件**
- `app.py`: 唯一的主应用文件,包含所有功能实现
- `config_groups.db`: SQLite数据库文件
### 关键功能模块
@@ -88,38 +86,34 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
### 环境设置
```bash
# 安装依赖仅需要Flask和cassandra-driver
# 安装依赖
pip install -r requirements.txt
# 运行应用默认端口5000
python app.py
# 自定义端口运行
# 修改app.py最后一行app.run(debug=True, port=5001)
# 修改app.py最后一行app.run(debug=True, port=XXXX)
```
### 调试和日志
```bash
# 应用启动后查询日志可通过以下API获取
# GET /api/query-logs - 获取查询日志
# DELETE /api/query-logs - 清空查询日志
# 日志级别INFO, WARNING, ERROR
# 所有Cassandra查询和SQL操作都会记录到查询日志中
```
### 测试和验证
```bash
# 运行分表功能测试(测试时间戳提取和分表索引计算)
python test_sharding.py
# 主要通过Web界面进行功能测试
# 单表查询测试http://localhost:5000/db-compare
# 分表查询测试在Web界面中开启分表模式
# 测试新的分表计算规则
python test_new_sharding.py
# 演示新分表规则的详细工作原理
python demo_new_sharding.py
# 测试查询日志功能
python test_query_logs.py
# 集成测试(分表功能 + 查询日志)
python test_integration.py
# 测试数据库连接和查询功能
# 通过Web界面http://localhost:5000/db-compare
# 或直接运行示例脚本:
python demo/Query.py
python demo/twcsQuery.py
# 数据库初始化如果config_groups.db不存在
# 通过访问Web界面会自动创建数据库表结构
```
### 开发模式
@@ -131,6 +125,12 @@ python demo/twcsQuery.py
- Flask==2.3.3
- cassandra-driver==3.29.1
### 项目特点
- **单文件架构**:所有后端逻辑都在 `app.py` 中实现1400+行代码)
- **内存日志系统**:使用 `QueryLogCollector` 类在内存中收集查询日志
- **SQLite本地存储**:配置组和查询历史存储在本地 `config_groups.db` 文件中
- **前端原生实现**使用原生JavaScript + Bootstrap无现代前端框架
## API架构说明
### 核心API端点
@@ -229,6 +229,19 @@ python demo/twcsQuery.py
## 开发注意事项
### 代码修改指导
- **单文件开发**:所有后端功能都在 `app.py` 中,修改时要注意代码结构清晰
- **数据库模式变更**修改SQLite表结构需要考虑向后兼容性
- **前端JavaScript**:位于 `static/js/app.js`使用原生JS注意浏览器兼容性
- **HTML模板**使用Jinja2模板引擎主要文件在 `templates/` 目录
### 核心类和函数位置app.py
- `QueryLogCollector`日志收集系统第20-46行
- `ShardingCalculator`分表计算器第64行开始
- 数据库连接:`create_cassandra_connection()`
- 查询比对:`execute_query()``execute_sharding_query()`
- API路由使用Flask装饰器定义
### 分表功能开发指导
- **时间戳解析(已更新)**`ShardingCalculator.extract_timestamp_from_key()` 新规则
- 使用 `re.sub(r'\D', '', key)` 删除所有非数字字符

53
app.py
View File

@@ -1,4 +1,4 @@
from flask import Flask, render_template, request, jsonify
from flask import Flask, render_template, request, jsonify, send_from_directory
from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider
import json
@@ -455,7 +455,7 @@ DEFAULT_CONFIG = {
'keyspace': '',
'table': ''
},
'keys': ['docid'],
'keys': [],
'fields_to_compare': [],
'exclude_fields': []
}
@@ -536,7 +536,9 @@ def get_config_group_by_id(group_id):
try:
cursor.execute('''
SELECT * FROM config_groups WHERE id = ?
SELECT id, name, description, pro_config, test_config, query_config,
sharding_config, created_at, updated_at
FROM config_groups WHERE id = ?
''', (group_id,))
row = cursor.fetchone()
@@ -552,25 +554,12 @@ def get_config_group_by_id(group_id):
'updated_at': row['updated_at']
}
# 添加分表配置(如果存在)
sharding_config_data = None
try:
# 尝试获取sharding_config字段
sharding_config_data = row[len(row) - 3] # sharding_config在倒数第三个位置
except (IndexError, KeyError):
# 如果字段不存在,尝试通过列名获取
# 添加分表配置
if row['sharding_config']:
try:
cursor.execute("PRAGMA table_info(config_groups)")
columns = cursor.fetchall()
column_names = [col[1] for col in columns]
if 'sharding_config' in column_names:
sharding_index = column_names.index('sharding_config')
sharding_config_data = row[sharding_index]
except:
pass
if sharding_config_data:
config['sharding_config'] = json.loads(sharding_config_data)
config['sharding_config'] = json.loads(row['sharding_config'])
except (json.JSONDecodeError, TypeError):
config['sharding_config'] = None
else:
config['sharding_config'] = None
@@ -1071,6 +1060,11 @@ def generate_recommendations(consistency_percentage, missing_in_test, missing_in
def index():
return render_template('index.html')
@app.route('/test-config-load')
def test_config_load():
"""配置加载测试页面"""
return send_from_directory('.', 'test_config_load.html')
@app.route('/db-compare')
def db_compare():
return render_template('db_compare.html')
@@ -1305,11 +1299,18 @@ def api_save_config_group():
description = data.get('description', '').strip()
pro_config = data.get('pro_config', {})
test_config = data.get('test_config', {})
query_config = {
'keys': data.get('keys', []),
'fields_to_compare': data.get('fields_to_compare', []),
'exclude_fields': data.get('exclude_fields', [])
}
# 获取查询配置,支持两种格式
if 'query_config' in data:
# 嵌套格式
query_config = data.get('query_config', {})
else:
# 平铺格式
query_config = {
'keys': data.get('keys', []),
'fields_to_compare': data.get('fields_to_compare', []),
'exclude_fields': data.get('exclude_fields', [])
}
# 提取分表配置
sharding_config = data.get('sharding_config')

View File

@@ -53,8 +53,8 @@ function toggleShardingMode() {
shardingConfig.style.display = 'block';
executeButton.textContent = '执行分表查询比对';
keyInputHint.textContent = '分表模式Key值应包含时间戳用于计算分表索引';
keysField.placeholder = 'wmid (推荐使用包含时间戳的字段)';
keysField.value = 'wmid';
keysField.placeholder = ' (推荐使用包含时间戳的字段)';
keysField.value = '';
// 更新查询Key输入框的占位符
const queryValues = document.getElementById('query_values');
@@ -64,8 +64,8 @@ function toggleShardingMode() {
shardingConfig.style.display = 'none';
executeButton.textContent = '执行查询比对';
keyInputHint.textContent = '单表模式输入普通Key值';
keysField.placeholder = 'docid';
keysField.value = 'docid';
keysField.placeholder = '';
keysField.value = '';
// 更新查询Key输入框的占位符
const queryValues = document.getElementById('query_values');
@@ -163,9 +163,33 @@ async function loadSelectedConfigGroup() {
document.getElementById('test_table').value = config.test_config.table || '';
// 填充查询配置
console.log('配置组查询配置:', config.query_config);
document.getElementById('keys').value = (config.query_config.keys || []).join(',');
document.getElementById('fields_to_compare').value = (config.query_config.fields_to_compare || []).join(',');
document.getElementById('exclude_fields').value = (config.query_config.exclude_fields || []).join(',');
console.log('填充后的字段值:');
console.log('keys:', document.getElementById('keys').value);
console.log('fields_to_compare:', document.getElementById('fields_to_compare').value);
console.log('exclude_fields:', document.getElementById('exclude_fields').value);
// 加载分表配置
if (config.sharding_config) {
// 设置分表启用状态
document.getElementById('enableSharding').checked = config.sharding_config.enabled || false;
toggleShardingMode();
// 填充分表配置
document.getElementById('use_sharding_for_pro').checked = config.sharding_config.use_sharding_for_pro || false;
document.getElementById('use_sharding_for_test').checked = config.sharding_config.use_sharding_for_test || false;
document.getElementById('pro_interval_seconds').value = config.sharding_config.interval_seconds || 604800;
document.getElementById('pro_table_count').value = config.sharding_config.table_count || 14;
document.getElementById('test_interval_seconds').value = config.sharding_config.interval_seconds || 604800;
document.getElementById('test_table_count').value = config.sharding_config.table_count || 14;
} else {
// 禁用分表模式
document.getElementById('enableSharding').checked = false;
toggleShardingMode();
}
showAlert('success', `配置组 "${config.name}" 加载成功`);
} else {
@@ -247,7 +271,9 @@ async function saveConfigGroup() {
body: JSON.stringify({
name: name,
description: description,
...config,
pro_config: config.pro_config,
test_config: config.test_config,
query_config: config.query_config,
sharding_config: shardingConfig
})
});
@@ -492,11 +518,13 @@ function getCurrentConfig() {
keyspace: document.getElementById('test_keyspace').value,
table: document.getElementById('test_table').value
},
keys: document.getElementById('keys').value.split(',').map(k => k.trim()).filter(k => k),
fields_to_compare: document.getElementById('fields_to_compare').value
.split(',').map(f => f.trim()).filter(f => f),
exclude_fields: document.getElementById('exclude_fields').value
.split(',').map(f => f.trim()).filter(f => f),
query_config: {
keys: document.getElementById('keys').value.split(',').map(k => k.trim()).filter(k => k),
fields_to_compare: document.getElementById('fields_to_compare').value
.split(',').map(f => f.trim()).filter(f => f),
exclude_fields: document.getElementById('exclude_fields').value
.split(',').map(f => f.trim()).filter(f => f)
},
values: document.getElementById('query_values').value
.split('\n').map(v => v.trim()).filter(v => v)
};
@@ -512,7 +540,7 @@ async function executeQuery() {
return;
}
if (!config.keys.length) {
if (!config.query_config.keys.length) {
showAlert('warning', '请输入主键字段');
return;
}
@@ -573,12 +601,11 @@ function getShardingConfig() {
return {
...baseConfig,
sharding_config: {
enabled: document.getElementById('enableSharding').checked,
use_sharding_for_pro: document.getElementById('use_sharding_for_pro').checked,
use_sharding_for_test: document.getElementById('use_sharding_for_test').checked,
pro_interval_seconds: parseInt(document.getElementById('pro_interval_seconds').value) || 604800,
pro_table_count: parseInt(document.getElementById('pro_table_count').value) || 14,
test_interval_seconds: parseInt(document.getElementById('test_interval_seconds').value) || 604800,
test_table_count: parseInt(document.getElementById('test_table_count').value) || 14
interval_seconds: parseInt(document.getElementById('pro_interval_seconds').value) || 604800,
table_count: parseInt(document.getElementById('pro_table_count').value) || 14
}
};
}
@@ -2660,11 +2687,7 @@ async function saveHistoryRecord() {
description: description,
pro_config: config.pro_config,
test_config: config.test_config,
query_config: {
keys: config.keys,
fields_to_compare: config.fields_to_compare,
exclude_fields: config.exclude_fields
},
query_config: config.query_config,
query_keys: config.values,
results_summary: currentResults.summary || {},
execution_time: 0.0,

View File

@@ -299,72 +299,6 @@
<div class="config-section">
<h4><i class="fas fa-cogs"></i> 配置管理</h4>
<!-- 查询模式切换 -->
<div class="card mb-3">
<div class="card-header">
<h6><i class="fas fa-toggle-on"></i> 查询模式</h6>
</div>
<div class="card-body">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="enableSharding" onchange="toggleShardingMode()">
<label class="form-check-label" for="enableSharding">
<strong>启用分表查询模式</strong>
<small class="text-muted d-block">支持TWCS时间分表的智能索引计算</small>
</label>
</div>
</div>
</div>
<!-- 分表参数配置 (默认隐藏) -->
<div class="sharding-config-section" id="shardingConfig" style="display: none;">
<h5><i class="fas fa-layer-group"></i> 分表参数配置</h5>
<div class="row">
<div class="col-md-6">
<h6 class="text-primary">生产环境分表配置</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="use_sharding_for_pro" checked>
<label class="form-check-label" for="use_sharding_for_pro">
启用分表查询
</label>
</div>
<div class="mb-2">
<label for="pro_interval_seconds" class="form-label">时间间隔(秒)</label>
<input type="number" class="form-control form-control-sm" id="pro_interval_seconds" value="604800" min="1">
<small class="form-text text-muted">默认604800秒(7天)</small>
</div>
<div class="mb-2">
<label for="pro_table_count" class="form-label">分表数量</label>
<input type="number" class="form-control form-control-sm" id="pro_table_count" value="14" min="1" max="100">
<small class="form-text text-muted">默认14张分表</small>
</div>
</div>
<div class="col-md-6">
<h6 class="text-success">测试环境分表配置</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="use_sharding_for_test">
<label class="form-check-label" for="use_sharding_for_test">
启用分表查询
</label>
</div>
<div class="mb-2">
<label for="test_interval_seconds" class="form-label">时间间隔(秒)</label>
<input type="number" class="form-control form-control-sm" id="test_interval_seconds" value="604800" min="1">
<small class="form-text text-muted">默认604800秒(7天)</small>
</div>
<div class="mb-2">
<label for="test_table_count" class="form-label">分表数量</label>
<input type="number" class="form-control form-control-sm" id="test_table_count" value="14" min="1" max="100">
<small class="form-text text-muted">默认14张分表</small>
</div>
</div>
</div>
<div class="alert alert-info mt-3" role="alert">
<i class="fas fa-info-circle"></i>
<strong>分表计算说明:</strong>系统会自动从Key值中提取时间戳并计算分表索引。
计算公式:<code>时间戳 // 间隔秒数 % 分表数量</code>
</div>
</div>
<!-- 配置组管理 -->
<div class="card mb-3">
<div class="card-header">
@@ -419,6 +353,77 @@
</button>
</div>
<!-- 查询模式切换 -->
<div class="card mb-3">
<div class="card-header">
<h6><i class="fas fa-toggle-on"></i> 查询模式</h6>
</div>
<div class="card-body">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="enableSharding" onchange="toggleShardingMode()">
<label class="form-check-label" for="enableSharding">
<strong>启用分表查询模式</strong>
<small class="text-muted d-block">支持TWCS时间分表的智能索引计算</small>
</label>
</div>
</div>
</div>
<!-- 分表参数配置 (默认隐藏) -->
<div class="sharding-config-section" id="shardingConfig" style="display: none;">
<div class="card mb-3">
<div class="card-header">
<h6><i class="fas fa-layer-group"></i> 分表参数配置</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6 class="text-primary">生产环境分表配置</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="use_sharding_for_pro" checked>
<label class="form-check-label" for="use_sharding_for_pro">
启用分表查询
</label>
</div>
<div class="mb-2">
<label for="pro_interval_seconds" class="form-label">时间间隔(秒)</label>
<input type="number" class="form-control form-control-sm" id="pro_interval_seconds" value="604800" min="1">
<small class="form-text text-muted">默认604800秒(7天)</small>
</div>
<div class="mb-2">
<label for="pro_table_count" class="form-label">分表数量</label>
<input type="number" class="form-control form-control-sm" id="pro_table_count" value="14" min="1" max="100">
<small class="form-text text-muted">默认14张分表</small>
</div>
</div>
<div class="col-md-6">
<h6 class="text-success">测试环境分表配置</h6>
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" id="use_sharding_for_test">
<label class="form-check-label" for="use_sharding_for_test">
启用分表查询
</label>
</div>
<div class="mb-2">
<label for="test_interval_seconds" class="form-label">时间间隔(秒)</label>
<input type="number" class="form-control form-control-sm" id="test_interval_seconds" value="604800" min="1">
<small class="form-text text-muted">默认604800秒(7天)</small>
</div>
<div class="mb-2">
<label for="test_table_count" class="form-label">分表数量</label>
<input type="number" class="form-control form-control-sm" id="test_table_count" value="14" min="1" max="100">
<small class="form-text text-muted">默认14张分表</small>
</div>
</div>
</div>
<div class="alert alert-info mt-3">
<strong>分表计算说明:</strong>系统会自动从Key值中提取时间戳并计算分表索引。
计算公式:<code>时间戳 // 间隔秒数 % 分表数量</code>
</div>
</div>
</div>
</div>
<!-- 生产环境配置 -->
<div class="card mb-3">
<div class="card-header d-flex justify-content-between align-items-center">
@@ -533,8 +538,8 @@
<div class="card-body">
<div class="mb-3">
<label class="form-label">主键字段 (逗号分隔)</label>
<input type="text" class="form-control form-control-sm" id="keys" placeholder="docid 或 wmid" value="docid">
<small class="form-text text-muted">分表模式下推荐使用包含时间戳的字段如wmid</small>
<input type="text" class="form-control form-control-sm" id="keys" placeholder="" value="">
<small class="form-text text-muted">分表模式下推荐使用包含时间戳的字段如</small>
</div>
<div class="mb-3">
<label class="form-label">比较字段 (空则比较全部,逗号分隔)</label>