删除以前版本文件
This commit is contained in:
65
CLAUDE.md
65
CLAUDE.md
@@ -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
53
app.py
@@ -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')
|
||||
|
@@ -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,
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user