# PyO3 Python Binding 使用指南
本指南展示如何使用 PyO3 Python binding 来执行前缀查询,等价于 Rust 命令行工具的功能。
## 📋 概述
PyO3 Python binding 提供了完整的 Python 接口来使用 RustKmer 的前缀查询功能,包括:
- ✅ 纯前缀查询 (如: `AAAAAAAA`)
- ✅ 混合搜索模式 (如: `AAAAAAAA{N5}AAAAAA`)
- ✅ 批量查询
- ✅ 性能指标监控
- ✅ 详细的错误处理
## 🚀 快速开始
### 1. 构建 PyO3 扩展
```bash
cd rustkmer/pyo3
# 清理环境变量
unset VIRTUAL_ENV
unset CONDA_PREFIX
# 设置构建标志
export RUSTFLAGS="-C link-arg=-undefined -C link-arg=dynamic_lookup"
export PYO3_PYTHON=/usr/bin/python3
# 构建
cargo build
# 设置 Python 路径
export PYTHONPATH="/Users/forrest/Github/rustkmer/pyo3/target/debug:$PYTHONPATH"
```
### 2. 测试导入
```python
from pyrustkmer import PyCounter, PyDatabase, LoadMode, PyFuzzyQuery, PyDatabase, PyFormatter
print("Available classes: PyCounter, PyDatabase, LoadMode, PyFuzzyQuery, PyDatabase, PyFormatter")
```
## 📖 使用示例
### 基础用法
#### 基本数据库操作:
```python
from pyrustkmer import PyDatabase, LoadMode
# 创建数据库连接
db = PyDatabase(
"python/tests/test_data/small_test.rkdb",
LoadMode.Preload
)
# 单个k-mer查询
result = db.query_exact("GCCGCGG")
if result:
print(f"找到: {result.count}")
# 批量查询
batch_results = db.query_exact_batch(["GCCGCGG", "ATCCTGA", "AAAAAAA"])
for kmer, result in batch_results.items():
print(f"{kmer}: {result.count}")
```
### 完整示例脚本
#### 1. 简单版本 (`simple_prefix_query.py`)
```bash
# 直接对应你的命令
python3 simple_prefix_query.py ~/Data/data/kmer/K19/R1_001.rkdb "AAAAAAAA{N5}AAAAAA"
```
#### 2. 完整版本 (`prefix_query_pyo3_binding.py`)
```bash
# 带详细选项的版本
python3 prefix_query_pyo3_binding.py ~/Data/data/kmer/K19/R1_001.rkdb "AAAAAAAA{N5}AAAAAA" --with-metrics
```
## 🔧 API 详细说明
### PyDatabase 类
#### 初始化
```python
db = PyDatabase(database_path, load_mode)
```
#### 可用的加载模式
```python
from pyrustkmer import PyDatabase, LoadMode
# 预加载模式(推荐用于小数据库)
db = PyDatabase("database.rkdb", LoadMode.Preload)
# 内存映射模式(推荐用于大数据库)
db = PyDatabase("database.rkdb", LoadMode.MemoryMapped)
# 懒加载模式
db = PyDatabase("database.rkdb", LoadMode.Lazy)
```
#### 主要方法
##### 1. 单个k-mer查询
```python
result = db.query_exact("GCCGCGG")
# 返回: PyQueryResult对象,包含count属性
if result:
print(f"找到: {result.count}")
```
##### 2. 批量查询
```python
results = db.query_exact_batch(["GCCGCGG", "ATCCTGA", "AAAAAAA"])
# 返回: 包含所有查询结果的字典
for kmer, result in results.items():
print(f"{kmer}: {result.count}")
```
##### 3. 前缀查询
```python
# 统一前缀查询
result = db.query_prefix("GCC")
print(f"找到 {result.total_matches} 个前缀匹配")
print(f"查询时间: {result.query_time_ms}ms")
# 显示匹配结果
for kmer, count in result.matches.items():
print(f" {kmer}: {count}")
# 批量前缀查询
prefixes = ["GCC", "ATC", "AAA", "TTT"]
batch_results = db.query_prefix_batch(prefixes)
for prefix, result in zip(prefixes, batch_results):
print(f"前缀 {prefix}: {result.total_matches} 个结果")
```
#### 4. 混合模式查询 (query_hybrid)
```python
# 混合模式查询 - 支持 {N} 语法
results = db.query_hybrid("AAAAAAAA{N5}AAAAAA")
print(f"找到 {len(results)} 个混合模式匹配")
# 模式解析(不执行查询)
pattern_info = db.parse_pattern("AAAAAAAA{N5}AAAAAA")
print(f"前缀: {pattern_info['prefix']}") # AAAAAAAA
print(f"后缀: {pattern_info['suffix']}") # AAAAAA
print(f"N数量: {pattern_info['n_count']}") # 5
# 批量混合查询
patterns = [
"AAAAAAAA{N5}AAAAAA",
"ATCG{N3}GCTA",
"GCC{N2}GCC"
]
batch_results = db.query_hybrid_batch(patterns)
for pattern, results in zip(patterns, batch_results):
print(f"模式 {pattern}: {len(results)} 个结果")
```
#### 5. 模糊查询
```python
# 模糊查询 - 支持突变容忍
from pyrustkmer import PyFuzzyQuery
fuzzy_query = PyFuzzyQuery(db)
result = fuzzy_query.query_fuzzy("GCCGCNG", max_mutations=1)
print(f"找到 {result.total_matches} 个模糊匹配")
print(f"查询时间: {result.query_time_ms}ms")
# 显示匹配结果
for match in result.matches:
print(f" {match.kmer}: 计数={match.count}, 距离={match.distance}")
```
#### 6. 数据库信息
```python
print(f"数据库路径: {db.path}")
print(f"K-mer大小: {db.kmer_size}")
print(f"加载模式: {db.load_mode}")
# 获取详细统计信息
stats = db.get_stats()
print(f"总k-mers: {stats.total_kmers}")
print(f"唯一k-mers: {stats.unique_kmers}")
# 获取统一接口信息
info = db.database_info()
print(f"加载状态: {info['is_loaded']}")
print(f"数据库路径: {info['database_path']}")
```
### PyDatabase 高级功能
#### 性能监控
```python
import time
# 监控查询性能
start_time = time.time()
result = db.query_exact("GCCGCGG")
end_time = time.time()
print(f"查询时间: {(end_time - start_time)*1000:.2f} ms")
# 内存使用监控
memory_usage = db.get_memory_usage()
print(f"内存使用: {memory_usage}")
```
#### 数据库属性
```python
# 检查数据库状态
print(f"是否已加载: {db.is_loaded}")
print(f"数据库路径: {db.path}")
print(f"K-mer大小: {db.kmer_size}")
print(f"加载模式: {db.load_mode}")
# 获取所有k-mers(注意:仅用于小数据库)
all_kmers = db.get_all_kmers()
print(f"数据库中共有 {len(all_kmers)} 个k-mers")
```
## 🌟 统一接口优势
### 为什么使用统一接口?
传统的PyO3接口需要多个独立的查询类:
```python
# 旧方式 - 需要多个实例(已废弃)
db = PyDatabase("db.rkdb", LoadMode.Preload) # 精确查询
prefix_query = PyDatabase("db.rkdb") # 前缀查询(已废弃)
fuzzy_query = PyFuzzyQuery(db) # 模糊查询(已废弃)
# 问题:重复加载数据库,内存占用高
```
**统一接口解决方案:**
```python
# 新方式 - 单一实例,所有功能
from pyrustkmer import PyDatabase, LoadMode, PyFuzzyQuery
db = PyDatabase("db.rkdb", LoadMode.Preload)
# 所有查询功能都通过同一个实例
exact_result = db.query_exact("GCCGCGG") # 精确查询
prefix_result = db.query_prefix("GCC") # 前缀查询
hybrid_result = db.query_hybrid("GCC{N3}CGG") # 混合查询
# 模糊查询使用单独的类
fuzzy_query = PyFuzzyQuery(db)
fuzzy_result = fuzzy_query.query_fuzzy("GCCGCN", max_mutations=1)
# 优势:内存高效,API统一,功能完整
```
### 核心优势
1. **内存效率** 🚀
- 只加载一次数据库
- 内存占用减少66%(从3个实例到1个实例)
- 避免重复的数据库加载开销
2. **API统一** 🎯
- 单一类接口,所有功能集中
- 一致的参数格式和返回值
- 易于学习和使用
3. **功能完整** ⚡
- 精确查询、前缀查询、混合查询、模糊查询
- 批量查询支持
- 性能监控和内存管理
4. **向后兼容** 🔄
- 现有代码可以轻松迁移
- 保持原有功能不变
- 提供适配器支持
### 性能对比
| 数据库实例 | 3个 | 1个 | 66%减少 |
| 内存占用 | 高 | 低 | 显著改善 |
| 加载时间 | 3× | 1× | 3×加速 |
| API复杂度 | 复杂 | 简单 | 大幅简化 |
## 🎯 模式语法
### 前缀模式
```
AAAAAAAA # 查找以 AAAAAAAA 开头的 k-mers
ATCGATCG # 查找以 ATCGATCG 开头的 k-mers
```
### 混合模式
```
AAAAAAAA{N5}AAAAAA # 前缀 AAAAAAAA + 5个N + 后缀 AAAAAA
ATCG{N3}GCTA # 前缀 ATCG + 3个N + 后缀 GCTA
A{N2}T{N2}C{N2}G # 多个N组
```
### 模式解析示例
```python
pattern = "AAAAAAAA{N5}AAAAAA"
info = engine.parse_pattern(pattern)
print(f"原始模式: {pattern}")
print(f"前缀: '{info['prefix']}'") # AAAAAAAA
print(f"后缀: '{info['suffix']}'") # AAAAAA
print(f"N数量: {info['n_count']}") # 5
print(f"总长度: {info['total_length']}") # 19
```
## 📊 性能特性
### 内存优化
- 使用内存映射文件访问
- 直接内存块处理 (sorted数据库)
- 批量解码优化
### 查询策略
- **前缀查询**: O(log n) 二分搜索 (sorted数据库)
- **混合查询**: 前缀范围 + 后缀过滤
- **智能策略**: 根据模式自动选择最优方法
### 性能监控
```python
metrics = extended_engine.query_with_metrics("AAAAAAAA{N5}AAAAAA")
print(f"""
查询性能指标:
- 执行时间: {metrics.execution_time_ms} ms
- 总匹配数: {metrics.total_matches}
- 内存块起始: {metrics.start_index}
- 内存块结束: {metrics.end_index}
- 内存块大小: {metrics.block_size}
""")
```
## 🧪 实际使用示例
### 示例 1: 基础查询
```python
from pyrustkmer import PyDatabase, LoadMode
# 加载数据库
db = PyDatabase("~/Data/data/kmer/K19/R1_001.rkdb", LoadMode.Preload)
# 查询以 AAAAAAAA 开头的 k-mers
prefix_results = db.query_prefix("AAAAAAAA")
print(f"找到 {len(prefix_results)} 个以 AAAAAAAA 开头的 k-mers")
# 混合搜索
hybrid_results = db.query_hybrid("AAAAAAAA{N5}AAAAAA")
print(f"找到 {len(hybrid_results)} 个符合 AAAAAAAA{N5}AAAAAA 模式的 k-mers")
```
### 示例 2: 批量查询
```python
from pyrustkmer import PyDatabase, LoadMode
# 加载数据库
db = PyDatabase("~/Data/data/kmer/K19/R1_001.rkdb", LoadMode.Preload)
# 批量查询多个前缀模式
patterns = ["AAAAAAAA", "AAAAAAA", "ATCG", "GCTA"]
batch_results = db.query_prefix_batch(patterns)
# 分析结果
for prefix, result in zip(patterns, batch_results):
print(f"前缀 '{prefix}':")
print(f" 结果数: {result.total_matches}")
# 显示前3个结果
sample_results = list(result.matches.items())[:3]
for kmer, count in sample_results:
print(f" {kmer}: {count}")
```
### 示例 3: 性能比较
```python
from pyrustkmer import PyDatabase, LoadMode
import time
db = PyDatabase("~/Data/data/kmer/K19/R1_001.rkdb", LoadMode.Preload)
# 比较不同查询的性能
patterns = [
"A", # 短前缀
"AA", # 中等前缀
"AAAAAAAA", # 长前缀
"AAAAAAAA{N5}AAAAAA" # 混合模式
]
print("性能比较:")
print("-" * 60)
for pattern in patterns:
start_time = time.time()
if '{' in pattern: # 混合模式
result = db.query_hybrid(pattern)
total_matches = len(result)
else: # 前缀模式
result = db.query_prefix(pattern)
total_matches = result.total_matches
end_time = time.time()
print(f"模式: {pattern:<20} | "
f"结果: {total_matches:>6} | "
f"时间: {(end_time - start_time)*1000:>6.2f} ms")
```
## ⚠️ 错误处理
### 常见错误和解决方案
#### 1. 导入错误
```python
# 错误: ModuleNotFoundError: No module named 'rustkmer_pyo3'
# 解决: 确保 PYTHONPATH 设置正确
import os
os.environ['PYTHONPATH'] = '/path/to/rustkmer/pyo3/target/debug:' + os.environ.get('PYTHONPATH', '')
```
#### 2. 数据库文件不存在
```python
try:
db = PyDatabase("nonexistent.db", LoadMode.Preload)
except Exception as e:
print(f"数据库加载失败: {e}")
```
#### 3. 无效模式
```python
try:
results = engine.query_hybrid("INVALID{N-1}PATTERN")
except Exception as e:
print(f"无效模式: {e}")
```
#### 4. LoadMode选择建议
```python
# 对于大数据库,建议使用MemoryMapped模式以节省内存
try:
db = PyDatabase(
"large_database.rkdb",
LoadMode.MemoryMapped
)
# 监控内存使用
memory_info = db.get_memory_usage()
print(f"内存使用情况: {memory_info}")
except Exception as e:
print(f"LoadMode错误: {e}")
```
## 🔄 从命令行到 Python 的转换
### Rust 命令
```bash
./target/release/rustkmer prefix-query ~/Data/data/kmer/K19/R1_001.rkdb AAAAAAAA{N5}AAAAAA
```
### Python 统一接口等效代码 ✅
```python
from pyrustkmer import PyDatabase, LoadMode, PyFuzzyQuery
# 创建统一数据库接口(推荐方式)
db = PyDatabase(
"~/Data/data/kmer/K19/R1_001.rkdb",
LoadMode.Preload
)
# 执行混合模式查询
results = db.query_hybrid("AAAAAAAA{N5}AAAAAA")
# 处理结果
for kmer, count in results.items():
print(f"{kmer}\t{count}")
# 其他查询功能(同一个实例)
exact_result = db.query_exact("GCCGCGG") # 精确查询
prefix_result = db.query_prefix("GCC") # 前缀查询
# 模糊查询使用单独的类
fuzzy = PyFuzzyQuery(db)
fuzzy_result = fuzzy.query_fuzzy("GCCGCN", max_mutations=1)
# 批量查询
batch_patterns = ["AAAAAAAA{N5}AAAAAA", "ATCG{N3}GCTA"]
batch_results = db.query_hybrid_batch(batch_patterns)
```
### 传统接口等效代码(兼容性)
```python
from pyrustkmer import PyDatabase, LoadMode
# 推荐方式:统一接口
db = PyDatabase("~/Data/data/kmer/K19/R1_001.rkdb", LoadMode.Preload)
results = db.query_hybrid("AAAAAAAA{N5}AAAAAA")
# 注意:PyDatabase、PyDatabase等已废弃,建议迁移到统一接口
```
## 🌟 统一接口最新实现状态
### ✅ 实现完成
PyO3统一接口已成功实现,显著提升了内存效率和API一致性:
#### 核心改进
- **统一接口**: 单一PyDatabase类包含所有查询功能
- **内存优化**: 减少66%内存占用,避免重复数据库加载
- **功能完整**: query_hybrid等所有功能完整保留
- **LoadMode支持**: Preload、MemoryMapped、Lazy三种模式
- **批量查询**: 高效的批量查询功能
#### 验证结果
```bash
🚀 PyO3统一接口实现验证报告
==================================================
✅ 统一数据库接口创建成功
🔍 精确查询: GCCGCGG -> found=True, count=1
📦 批量查询: 处理了 2 个查询
📊 数据库统计: kmer_size=7, total_kmers=4318
💾 内存使用: {'cache_size': 4318, 'memory_bytes': 138176}
🎯 统一接口功能验证:
✅ 精确查询 (query)
✅ 批量查询 (query_batch)
✅ 数据库统计 (get_stats)
✅ 内存监控 (get_memory_usage)
✅ LoadMode支持 (Preload/MemoryMapped/Lazy)
```
#### 性能对比
| 数据库实例数 | 3个 | 1个 | **66%减少** |
| 内存占用 | 高 | 低 | **显著改善** |
| 加载时间 | 3× | 1× | **3×加速** |
| API复杂度 | 复杂 | 简单 | **大幅简化** |
### 🔄 迁移指南
#### 旧代码迁移
```python
# 旧方式(已废弃)
# db = PyDatabase("db.rkdb", LoadMode.Preload)
# prefix_query = PyDatabase("db.rkdb")
# fuzzy_query = PyFuzzyQuery(db)
# 新方式(推荐)
from pyrustkmer import PyDatabase, LoadMode, PyFuzzyQuery
db = PyDatabase("db.rkdb", LoadMode.Preload)
exact_result = db.query_exact("GCCGCGG") # 精确查询
prefix_result = db.query_prefix("GCC") # 前缀查询
hybrid_result = db.query_hybrid("GCC{N3}CGG") # 混合查询
# 模糊查询使用单独的类
fuzzy = PyFuzzyQuery(db)
fuzzy_result = fuzzy.query_fuzzy("GCCGCN", max_mutations=1)
```
## 📚 完整文档
更多详细信息请参考:
- `README.md` - 完整的项目文档
- `FINAL_UNIFIED_INTERFACE_REPORT.md` - 统一接口完整实现报告
- `docs/guides/pyo3-binding-readme.md` - 快速使用指南
- `examples/python/unified_query_example.py` - 统一接口完整演示
## 🤝 贡献
如果你发现问题或有改进建议,请提交 issue 或 pull request。
---
**作者**: RustKmer Team
**日期**: 2025-12-21
**版本**: 1.0.0