ライブドアのレコメンドエンジン シシンデラ(cicindela)
アイテムオンリーでしか使ってなかったから
カテゴリーがidしか入力できないと言うのを初めて知ったw
userとitemは
{cicindela_home}/lib/Cicindela/Config/_common.pmのフィルタに
use_user_char_id=>1,
use_item_char_id=>1,
って書いたら自動的にcharからidに変換してくれるのだけどー
categoryは無いな。
use_category_char_id=>1みたいなのをコピーで作るか?w
ちょっとやってみた。
cicindelaカスタマイズ
use_category_char_id=>1の実装
cicindelaのデータの投入のしかたは
xxxx_bufferという名前のテーブル
からxxxxのテーブルにデータが
flush_buffers.plによって移動されるので
まずcategory_bufferのテーブル構造を変更する。
cicindela.sqlの
drop table if exists categories_buffer;
create table categories_buffer (
id int not null auto_increment primary key,
item_id int,
item_char_id varchar(255),
category_id int,
is_delete tinyint(1) not null default 0,
timestamp timestamp not null default CURRENT_TIMESTAMP
) engine = innodb;
これを
drop table if exists categories_buffer;
create table categories_buffer (
id int not null auto_increment primary key,
item_id int,
item_char_id varchar(255),
category_id int,
category_char_id varchar(255),
is_delete tinyint(1) not null default 0,
timestamp timestamp not null default CURRENT_TIMESTAMP
) engine = innodb;
とする。
あと、新しいテーブルcategory_id_char2intを
作成する必要があるので
drop table if exists category_id_char2int;
create table category_id_char2int (
id int not null auto_increment primary key,
char_id varchar(255) not null,
timestamp timestamp not null default CURRENT_TIMESTAMP,
unique key (char_id),
key (timestamp)
) engine = innodb;
を一番最後に追記(最後じゃなくても別にいいけどさ)
次に
lib/Cicindelaの配下
IncomingData.pmの中に
# int以外の型のidの変換用
と言うコメントがあるので
# int以外の型のidの変換用
'insert_user_char_id' => q{
insert ignore into user_id_char2int (char_id) values (?)
},
'insert_item_char_id' => q{
insert ignore into item_id_char2int (char_id) values (?)
},
これを
# int以外の型のidの変換用
'insert_user_char_id' => q{
insert ignore into user_id_char2int (char_id) values (?)
},
'insert_item_char_id' => q{
insert ignore into item_id_char2int (char_id) values (?)
},
'insert_category_char_id' => q{
insert ignore into category_id_char2int (char_id) values (?)
},
とする。
さっきの # int以外の型のidの変換用のすぐ下に
今度はresolve_xxx_idsってのがあるからそれも追加する。
'resolve_user_ids' => q{
update %$buffer_table a, user_id_char2int b
set a.user_id = b.id
where a.id <= ? and a.user_char_id = b.char_id
},
'resolve_item_ids' => q{
update %$buffer_table a, item_id_char2int b
set a.item_id = b.id
where a.id <= ? and a.item_char_id = b.char_id
},
を
'resolve_user_ids' => q{
update %$buffer_table a, user_id_char2int b
set a.user_id = b.id
where a.id <= ? and a.user_char_id = b.char_id
},
'resolve_item_ids' => q{
update %$buffer_table a, item_id_char2int b
set a.item_id = b.id
where a.id <= ? and a.item_char_id = b.char_id
},
'resolve_category_ids' => q{
update %$buffer_table a, category_id_char2int b
set a.category_id = b.id
where a.id <= ? and a.category_char_id = b.char_id
},
にする。
次、sub insert_categoryを変更
sub insert_categoryの中で
変数を定義しているところがあるが新しく
$category_char_idを作成するので
my ($item_char_id);を
my ($item_char_id,$category_char_id)として
if ($self->{use_category_char_id}) {
$category_char_id = $category_id; undef($category_id);
$self->sql('insert_category_char_id')->execute($category_char_id) or db_error;
}
を追加し、
$self->sql('insert_categories_buffer')->execute($category_id, $item_id, $item_char_id, $is_delete)
or db_error;
となっているのを
$self->sql('insert_categories_buffer')->execute($category_id,$category_char_id,$item_id, $item_char_id, $is_delete)
or db_error;
とする。
引数を変更したので
'insert_categories_buffer' => q{
insert into categories_buffer (category_id, item_id, item_char_id, is_delete, timestamp) values (?, ?, ?, ?, now())
},
これを
'insert_categories_buffer' => q{
insert into categories_buffer (category_id, category_char_id, item_id, item_char_id, is_delete, timestamp) values (?, ?, ?, ?, ?, now())
},
とする。
次 sub flush_buffers
に
if ($max_id) {
# $LOGGER->debug("flushing $self->{buffer_table} up to id $max_id");
if ($self->{use_user_char_id} and $self->_find_column_in_buffer_table('user_id')) {
$self->sql('resolve_user_ids')->execute($max_id) or db_error;
}
if ($self->{use_item_char_id} and $self->_find_column_in_buffer_table('item_id')) {
$self->sql('resolve_item_ids')->execute($max_id) or db_error;
}
eval {
$self->sql('flush_buffer2_insert')->execute($max_id);
$self->sql('flush_buffer2_delete')->execute($max_id);
$self->sql('flush_buffer3')->execute($max_id);
};
$LOGGER->info($@) if $@; # 解析のためにロックかかってて失敗するのは構わない
}
と言う記述があるのでこれを
if ($max_id) {
# $LOGGER->debug("flushing $self->{buffer_table} up to id $max_id");
if ($self->{use_user_char_id} and $self->_find_column_in_buffer_table('user_id')) {
$self->sql('resolve_user_ids')->execute($max_id) or db_error;
}
if ($self->{use_item_char_id} and $self->_find_column_in_buffer_table('item_id')) {
$self->sql('resolve_item_ids')->execute($max_id) or db_error;
}
if ($self->{use_category_char_id} and $self->_find_column_in_buffer_table('category_id')) {
$self->sql('resolve_category_ids')->execute($max_id) or db_error;
}
eval {
$self->sql('flush_buffer2_insert')->execute($max_id);
$self->sql('flush_buffer2_delete')->execute($max_id);
$self->sql('flush_buffer3')->execute($max_id);
};
$LOGGER->info($@) if $@; # 解析のためにロックかかってて失敗するのは構わない
}
とする。
以上。とりあえずデータを入れるところは問題無いと思われる。
(誰か人柱になってw)