SequenceIterator
SequenceIterator 类用于管理类型为序列的数据库字段。
正如在“在 Python 中使用序列”页面中所解释的那样,C++ 序列实例本质上是序列值向量的迭代器。序列字段本质上是一个动态值数组,在 Python 应用程序中由符合 Python 元组的 SequenceIterator 方法进行管理。有关使用序列进行 Python 编程的示例,请参阅“使用序列字段”教程页面。 大多数 SequenceIterator 方法通常被称为分析方法,并根据要执行的操作类型进行分组。有关这些方法的详细描述,请参阅“按类别划分的分析方法”页面。
使用序列
正如《用户指南》页面中所解释的那样,序列是 SmartEDB 支持的标量数据元素的无界数组。Python 中的 SequenceIterator 类用于管理类型为序列的数据库字段。由于序列实际上是值的向量,因此通过迭代器来访问它们。在 C 应用程序中使用 C 类型 mco_seq_iterator_h 的地方,在 Python 应用程序中 SequenceIterator 类则发挥着相同的作用。SequenceIterator 类还提供了一组强大的分析方法,用于对序列执行数学和统计运算。
插入和更新序列
通常,序列数据是通过 SequenceIterator 的 append() 方法插入的。例如,考虑以下模式定义:
#define uint4 unsigned<4>
class Quote {
char<16> symbol;
sequence<uint4 asc> day;
sequence<float> price;
tree<symbol> by_symbol;
};
有了这个类定义,Quote 序列字段 day 和 price 就可以用如下代码进行填充:
con.startTransaction()
tick = generate_random_quote()
quote = con.new("Quote")
quote.symbol = tick.symbol
quote.day.append(tick.day)
quote.price.append(tick.price)
con.commit()
有时可能需要向有序的时间序列中插入值。可以使用 insert() 方法将值插入到现有序列中。例如,以下代码片段查找具有“IBM”符号的 Quote 对象,然后插入日期和价格值:
con.startTransaction()
for quote in cursor:
dayit = quote.day.search(20130101, exdb.SeqIteratorBoundary.MCO_SEQ_BOUNDARY_INCLUSIVE,
20130101, exdb.SeqIteratorBoundary.MCO_SEQ_BOUNDARY_INCLUSIVE)
dayit = append(20130102)
quote.day.next()
quote.day.insert(dayit)
con.commit()
NumPy 的序列接口
如果 Python 已安装了 numPy 模块,那么就有可能直接从序列加载和保存数据到 numPy 数组中。(请注意,由于 SmartEDB 中序列数据的特性,仅支持 1 维的 numPy 数组。)
将一个 NumPy 数组附加到序列中
SequenceIterator 的 append() 方法可以接受一个 numpy.ndarray 作为参数。例如:
>>> ac = numpy.arange(10, dtype='uint32')
>>> ac
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint32)
>>> quote.volume.append(ac)
NumPy 和 SmartEDB 序列都使用 C 风格的二进制数组表示形式以提高效率。因此,序列和 nparray 的数据类型必须匹配。这就是为什么指定 dtype=uint32 作为参数的原因。
append() 方法识别以下参数类型:
o.price.append(1) // Python 对象
这将只是在序列的末尾添加一个值。(这是更新序列最慢的方式。)
o.price.append([1,2,3,4,5]) // Python 列表
这里列表中的 5 个值被添加到了序列的末尾。
o.price.append( (1,2,3,4,5) ) // Python 元组
列表中的 5 个值再次被添加到序列中。
Python 标准库支持同类型数组,其元素大小相同。实际上,这是对 C 风格数组的封装,可以像下面这样用它来填充一个序列:
import array
a = array.array('f', [1,2,3,4])
o.price.append(a)
从数据库的角度来看,这是插入数据的最快方式,但请记住以下几点考虑因素:
array.array
的数据类型必须与数据库序列的数据类型完全匹配。SmartEDB 数据库类型、Python 类型和 C 类型之间的类型映射如下表所示:序列类型 数组的类型码 C语言中的数据类型 signed<1> 'b' signed char unsigned<1> 'B' unsigned char signed<2> 'h' signed short unsigned<2> 'H' unsigned short signed<4> 'i' signed int unsigned<4> 'I' unsigned int signed<8> 'l' signed long long unsigned<8> 'L' unsigned long long float 'f' float double 'd' double char<n> - -
请注意,char<n> 类型在 array.array 中不受支持。
- 速度。尽管这是将数据插入数据库的最快方式,但创建 array.array 本身会产生开销。测试表明,用于插入的数组越长,性能提升就越明显。(使用包含 100 多个项目的数据块填充 array.array 是可行的。)此外,Python 解释器在向 array.array 填充值时速度相当慢。使用其他方法填充该数组可以实现真正的优势,例如:array.fromfile(f, n) 或 array.fromstring(s)。(请查阅 Python 文档以获取这些方法的相关信息。)
将序列数据检索到一个 NumPy 数组中
如果序列的大小适中,则可以使用 SequenceIterator 方法 tonparray() 将整个序列表示为一个 numPy 数组。其签名如下:
SequenceIterator.tonparray([size_hint])
对于已实例化的序列,SmartEDB 运行时确切地知道序列的大小,因此会立即为生成的数组分配所需的内存。对于未实例化的序列,无法提前得知生成数组的大小。在这种情况下,随着临时结果的构建,内存会按块分配。这效率不高,所以如果应用程序知道预期的数组大小,可以将其作为 size_hint 参数传递给 tonparray() 函数。
Python 嵌入式 SQL 应用程序中的序列
SmartEDB Python 包装器通过允许对序列进行操作来扩展 Python 数据库 API 规范。序列可能是 select 语句的结果,或者作为 insert 或 update 语句中的参数出现。例如,可以将以下语句发送到 SQL 引擎:
cursor.execute("SELECT stamp, low, high FROM Quote WHERE symbol = ?", ('AAA',))
此查询的结果可以如下所示:
row = cursor.fetchone()
print "Row is:", row
Row is: (<exdb.SequenceIterator object at 0x1008f6610>, <exdb.SequenceIterator object at 0x1008f7610>,
<exdb.SequenceIterator object at 0x1008f8610>)
请注意,生成的行包含作为行值的 SequenceIterator 对象。可以将常规的迭代器方法应用于此迭代器。请注意,除非是查询结果,否则返回的迭代器将是“未实例化”的。
要将数据插入到序列中,请使用 array.array 将数据作为参数传递到 SQL 语句中。例如:
cursor.execute('INSERT INTO Quote(symbol, stamp, open, close, high, low, volume) VALUES (?,?,?,?,?,?,?)',
('AAA', array.array('I', timestamps), array.array('f', opens), array.array('f', closes),
array.array('f', highs), array.array('f', lows), array.array('I', volumes)))
请注意,array.array
是严格类型的,因此其类型必须与序列列类型匹配。如果不匹配,结果行为将不可预测。不支持将 Python 列表或元组作为参数值传递。请查阅上面的映射表以获取序列类型与 array.array
类型之间的对应关系。