1400万行のデータをRubyで扱うと...?(C/C++でリベンジ編)
Posted 12月 29th, 2006 by hippos
1400万行のデータをRubyで扱うと...?で玉砕したのでここはC/C++で書いてみることにしました。C/C++の場合、使い捨ても業腹なので簡単なベースクラスを作成し派生クラスで対応することにします。ベースクラスでは今回必要なものだけを実装し、再利用するようなことがあれば逐次追加していくつもりです。(サンプルソースからはエラー処理を端折っています。)
static char* server_args[] = {
"MySQLBase.cpp","--datadir=/usr/local/mysql/var","--key_buffer_size=32M"
};
static char* server_groups[] = {
"embedded","server","this_program_SERVER",(char *)NULL
};
class CMySQLBase {
protected:
MYSQL* m_db;
MYSQL_RES* m_res;
public:
CMySQLBase(void);
virtual ~CMySQLBase(void);
virtual int run(int argc,char* argv[]) = 0;
protected:
int init(void); // 初期化処理
int end(void); // 終了処理
bool conn(const char* dbname); // コネクト処理
bool query(const char* query); // クエリ発行
void get_result(void); //結果の取得
MYSQL_ROW get_row(void); //行の取得
unsigned int get_field(void); //フィールド数の取得
};
このとき、それぞれのメソッドの実装は以下のとおり。
int CMySQLBase::init(void) {
int r = mysql_library_init(
sizeof(server_args)/sizeof(char *),server_args,server_groups);
if (!r) m_db = mysql_init(NULL);
return r;
}
int CMySQLBase::end(void){
mysql_close(m_db);
mysql_library_end();
}
bool CMySQLBase::conn(const char* dbname){
return mysql_real_connect(
m_db,NULL,"mysql","xxx",dbname,0,NULL,0) ? true : false;
}
bool CMySQLBase::query(const char* query){
return mysql_query(m_db,query) == 0 ? true : false;
}
void CMySQLBase::get_result(void){
m_res = mysql_store_result(m_db);
}
MYSQL_ROW CMySQLBase::get_row(void){
return mysql_fetch_row(m_res);
}
unsigned int CMySQLBase::get_field(void){
return mysql_num_fields(m_res);
}
このベースクラスから今回処理用の派生クラスを作成します。派生クラスのコンストラクタでベースクラスのinit()/conn()をデストラクタでend()を呼び出します。後は、呼び出し元からget_record()でレコードを取得します。
class foo : public CMySQLBase {
public:
foo(void){id=category=price=0;init();conn('db1');};
virtual ~foo(void){end();};
bool get_record(const char* id);
int get_category(void);
int get_price(void);
private:
int category;
int price;
};
===
bool foo::get_recorde(const char* id){
string q = "select category,price from foo where id = ";
q.append(id);
if (!query(q.c_str())) return false;
get_result();
MYSQL_ROW row = get_row();
category = atol(row[0]);
price = atol(row[1]);
return true;
}
int foo::get_category (void){
return category;
}
int foo::get_price(void){
return price;
}
これでようやく準備完了。あとはCSVを読み込んでまわす処理を作成します。ccsvクラスはプログラミング作法のサンプルを使用したCSV処理クラス(昔から愛用しています)
ifstream in;
ofstream out;
in.open(argv[1],ios::in);
ccsv csv(in);
foo _foo;
string line;
string id;
char buff[1024];
while(csv.getline(line)){
if (id.compare(csv.getfield(0)) != 0){
id = csv.getfield(0);
_foo.get_record(id.c_str());
}
memset(buff,0x00,sizeof(buff));
sprintf(buff,"%s,%d,%s,%s,%d,%s\n",
id.c_str(),
_foo.get_category(),
csv.getfield(1).c_str(),
csv.getfield(3).c_str(),
_foo.get_price(),
csv.getfield(2).c_str());
out << buff;
}
これで、万端。果たして結果は19分!なんとか使い物になりそうです。ふうぅ~。それにしても疲れました。今更ながらRubyの楽ちんさが身に沁みました。
この記事のトラックバックURL:
http://hippos-lab.com/blog/trackback/94


最近のコメント
14 weeks 4 days ago
49 weeks 2 days ago
1年 14 weeks ago
1年 14 weeks ago
1年 31 weeks ago
1年 31 weeks ago
1年 31 weeks ago
1年 43 weeks ago
1年 43 weeks ago
2 years 23 weeks ago