[Translate] 从SQL数据库迁移到Riak

news/2024/7/3 11:47:58

例子

关系数据库: 创建表

CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    author VARCHAR(30) NOT NULL,
    title VARCHAR(50) NOT NULL,
    body TEXT NOT NULL,
    created DATE NOT NULL
);

关系数据库: 查询

SELECT * FROM posts WHERE id = 99;

关系数据库: 查询结果

 id |   author   |             title              |            body            |  created
----+------------+--------------------------------+----------------------------+------------
 99 | John Daily | Riak Development Anti-Patterns | Writing an application ... | 2014-01-07

基本转换和存储过程如下

  • 每一个表行被转换为一个JSON对象,包含除id字段外的所有其他字段.

  • id字段不会存储在Riak中的JSON对象中. 它不会作为对象的键. 而是把标题作为键, 30字符长度限制, 小写, 并且用-作为单词之间的连字符. 比如上面的例子把riak-development-anti-patterns作为键.

  • 所有产生自posts表的JSON对象存储在名为posts的单个Riak桶当中.

  • 键存在在Riak set中, 需要的时候, 使所有对象可以被一次查询出来.

把Table转换为List

下面, 我们使用psycopg2库来把表转换为列表

import psycopg2
connection = psycopg2.connection('dbname=blog_db')
cursor = connection.cursor()

用该游标(cursor)执行SELECT * FROM posts查询,然后使用fetchall函数从游标当中获取信息:

cursor.execute('SELECT * FROM posts')
table = cursor.fetchall()

table对象由一个Python元组列表构成, 如下:

[(1, 'John Doe', 'Post 1 title', 'Post body ...', datetime.date(2014, 1, 1)),
 (2, 'Jane Doe', 'Post 2 title', 'Post body ...', datetime.date(2014, 1, 2)),
 # more posts in the list
]

转换行为JSON对象

上面的代码把posts表中的每一行数据转换为包含5个元素的元组, 为了更好的进行转换, 我们把元组转换为能够在Riak中更好的处理的Python字典数据类型, 官方的Riak Python客户端能够自动地把Python字段转换为能够在Riak中存储的JSON对象. 一旦我们有了一个字典列表, 就可以直接在Riak中存储这些字典类型的数据.

下面通过Python代码把数据库中的数据转换为JSON格式:

import datetime

def convert_row_to_dict(row):
    return {
        'author': row[1],
        'title': row[2],
        'body': row[3],
        'created': row[4].strftime('%m-%d-%Y')
    }

产生如下的JSON数据:

{
  'author': 'John Daily',
  'title': 'Riak Development Anti-Patterns',
  'body': 'Writing an application ...',
  'created': '01-07-2014'
}

存储行对象

现在使用store_row_in_riakposts表中的数据存储到Riak中:

  • 用博客的标题来构造键, 获取签名30字符, 字符全部转换为小写, 并用-替换空格.

  • 每行将被转换为一个正确的Riak对象,并存储

下面是这个函数的实现:

bucket = client.bucket('posts')

def store_row_in_riak(row):
    key = row[2][0:29].lower().replace(' ', '-') 
    obj = RiakObject(client, bucket, key)
    obj.content_type = 'application/json'
    obj.data = convert_row_to_dict(row)
    obj.store()

上面我们在一个Riak set存储所有对象的键, 以帮助我们在将来能够查询这些对象. 我们修改上的store_row_in_riak函数添加每一个键到一个set(集合):

from riak.datatypes import Set

objects_bucket = client.bucket('posts')
key_set = Set(client.bucket_type('sets').bucket('key_sets'), 'posts')

def store_row_in_riak(row):
    key = row[0]
    obj = RiakObject(client, bucket, key)
    obj.content_type = 'application/json'
    obj.data = convert_row_to_dict(row)
    obj.store()

现在,我们编写一个迭代器用于存储所有的行:

# Using our "table" object from above:

for row in table:
    store_row_in_riak(row)

一旦所有对象存储到Riak, 我们可以执行正常的键/值操作来一个一个地获取. 下面是一个使用Riak HTTP API的例子:

curl http://localhost:8098/buckets/posts/keys/99

这将返回一个博客(Blog)对象:

{
  "author": "John Daily",
  "title": "Riak Development Anti-Patterns",
  "body": "Writing an application ...",
  "created": "01-07-2014"
}

需要的时候, 我们也可以一次获取所有这些对象. 前面我们在Raik set中存储了所有对象的键. 我们可以编写一个函数从set中获取所有对象的key, 以及和这些key相关的所有对象:

from riak.datatypes import Set

set_bucket = client.bucket_type('sets').bucket('key_sets')
posts_bucket = client.bucket('posts')

def fetch_all_objects(table_name):
    keys = Set(client, bucket, table_name)
    for key in keys:
        return posts_bucket.get(key)

fetch_all_objects('posts')

这回返回之前存储的Python字典的完整列表.

使用二级索引

添加一个关键字字段(keywords), 来描述一篇博客的关键字列表:

CREATE TABLE posts (
    id SERIAL PRIMARY KEY,
    author VARCHAR(30) NOT NULL,
    title VARCHAR(50) NOT NULL,
    body TEXT NOT NULL,
    created DATE NOT NULL,
    keywords TEXT[] NOT NULL
);

插入数据:

INSERT INTO posts (author, title, body, created, keywords) VALUES
    ('Basho', 'Moving from MySQL to Riak', 'Traditional database architectures...',
    current_date, '{"mysql","riak","migration","rdbms"}');

为没一个博客的关键字列表添加一个二级索引. 下面我们编写一个函数对每一个关键字附加一个二级索引.

def add_keyword_2i_to_object(obj, keywords):
    for keywork in keywords:
        obj.add_index('keywords_bin', keyword)

然后我们可以插入该函数到store_row_in_riak函数中:

bucket = client.bucket('posts')

def store_row_in_riak(row):
    obj = RiakObject(client, bucket, row[0])
    obj.content_type = 'application/json'
    obj.data = convert_row_to_dict(row)
    add_keyword_2i_to_object(obj, row[5])
    obj.store()

现在我们可以基于一篇博客的关键字来查询:

bucket = client.bucket('posts')

def fetch_posts_by_keyword(keyword):
    for key in bucket.get_index('keywords_bin', keyword):
        return bucket.get(key)

该函数会返回所有包含特定关键字的博客列表.


http://www.niftyadmin.cn/n/2498328.html

相关文章

学python最好的书籍_学习Python有什么好的书籍推荐?

学习Python的朋友们越来越多,当当网和京东上面的Python类编程书籍,也从几年前寥寥无几到现在多的不知道选哪本才好了的地步。无论是自学还是参加培训班跟着老师学习,我们都需要几本实用的Python书,系统全面的掌握Python编程的相关…

c++调用栈库函数_C语言在ARM中函数调用时,栈是如何变化的?

为什么会写篇栈变化的文章?做系统分析的话你肯定遇到过一些crash, oops等棘手问题,一般大家都会用 gdb, objdump 或者 addr2line等工具分析 pc 位置来定位出错的地方。但是这些分析工具背后的本质原理就不见得理解深刻了,而且有的时候面对一系…

Python标准库:内置函数reversed(seq)

本函数是返回序列seq的反向訪问的迭代子。样例:#reversed()for i in reversed([2, 3, 4, 5]):print(i, end ,)结果输出例如以下:5,4,3,2,蔡军生 QQ:9073204 深圳

go 手动释放内存_golang 内存管理

1、虚拟内存、物理内存和页表每一个进程都有自身的虚拟内存,通过页表将虚拟内存映射到物理内存。虚拟内存空间被内核划分为了等长的部分,这部分称之为页,物理内存也被划分为了同样大小的页,通常称之为页帧。不同的虚拟内存空间中的…

python标准图示_3D图示Python标准自学教程基础篇(4)_文件处理

内容简介:本套课程为Python基础篇的第4套课程,主要讲解python文件处理的系统知识体系。首先讲解Python文件的概念以及常用读写函数open()、Read()、write()、close()以及文件读写访问标志。 其次讲解文件的典型应用文件的复制算法,以及with a…

java开发环境搭建-1

安卓开发所需软件: JDK Eclipse Android-Sdk ADT 其中jdk的下载和安装,详细见http://www.cnblogs.com/zhuxiaohui/p/3620685.html eclipse的下载地址为http://www.eclipse.org/downloads/,即选择当前版本【Eclipse IDE for Java EE Developer…

晚会现场屏幕控制软件_双11晚会呼声最高的主持人,不是汪涵也不是谢娜!

双11刚刚结束,很多人在双11前夕投入过多精力计算如何买最划算,以至于错过了双11晚会。今年双11晚会的阵容非常强大,而且天猫和苏宁易购都各自邀请嘉宾举办了为购物而生的晚会。如果你没看,没关系,网络上还可以重播&…

junit依赖_Java 单元测试Junit

一、 测试分类:1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。2. 白盒测试:需要写代码的。关注程序具体的执行流程。二、 Junit使用:白盒测试* 步骤:1. 定义一个测试类(测试用…