2010年3月10に行われた、情報処理学会創立50周年記念全国大会内
招待講演「CGMの現在と未来:初音ミク、ニコニコ動画、ピアプロの切り拓いた世界」内で発表したスライドです。
はじめに
この記事では、MySQL を使って簡単なメッセージキューを手軽に実装する方法を解説します。
メッセージキューとは、メッセージを一時的に溜めておき、順次処理するための仕組みです。迅速なレスポンスが必要な Web アプリケーションにおいて、時間のかかる処理を非同期に行うために、バックグラウンドで順次処理していくような場合に利用できます。
簡単なメッセージキューと言っても、大規模な運用にも耐えられる程度の速度と堅牢性を持ちます。
また、ここで解説している方法で作られたメッセージキューは、弊社ウェブサービスであるニコニコ動画に最近追加されたtwitter連携機能でも利用しています。
メッセージキューを作るにあたって
今回実装するメッセージキューは
- メッセージの追加(push)を高速に行う事ができる
- メッセージの取得(pop)はある程度高速に行う事ができる
- 多くのクライアントから同時に push/pop を行っても矛盾が発生しない
- MySQL に特別な拡張を必要としない
事を目指します。
Q4M について
MySQL 上で動作するキューエンジンとしては、サイボウズ・ラボ様によって開発・保守されている Q4M が有名です。MySQL5.1 系で動作するプラガブルストレージエンジンとして実装されていて、SQL を利用してキューの操作を行う事ができます。
残念ながらニコニコ動画では MySQL 5.0 系を利用しており、Q4M の利用は諦めざるを得ませんでしたが、MySQL 自体は既に何年も運用していてノウハウがあり、それを活かしたいので、特に拡張機能を使わずに独自のメッセージキューを実装する事にしました。
InnoDB を利用
ニコニコ動画では、基本的に MySQL 組み込みのストレージエンジンである InnoDB を利用しています。
InnoDB は高度なメモリキャッシュ機構と ACID を満たすトランザクション機構を備え、パフォーマンスに優れたストレージエンジンです。
今回実装するメッセージキューは、MySQL の基本機能を利用して作るため、ストレージエンジンがある程度自由に選ぶ事ができます。今回は InnoDB を利用します。
実装方法
メッセージキューテーブルを作成
メッセージキューが保存されるテーブルとして、以下の test_queue テーブルを作成します。
CREATE TABLE test_queue (
`id` BIGINT UNSIGNED NOT NULL
AUTO_INCREMENT,
`locked_until` TIMESTAMP NOT NULL
DEFAULT "0000-00-00 00:00:00",
`data` BLOB NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
テーブル中のカラムはそれぞれ、
- id: プライマリキーとなる数値ID
- locked_until: ロックが無効となる日時
- data: メッセージ内容
を表します。
基本的にメッセージの内容は data カラムに収まる事を想定していますが、例えば優先度付きキューを作るためにカラムを追加する事も可能です。
メッセージの追加
メッセージキューの末尾にメッセージを追加するには、単に INSERT をするだけです。
INSERT INTO test_queue SET data = "message body";
メッセージ内容である data カラムのみ指定します。単なる INSERT 操作であるため、高速です。
また、矛盾が発生しない事はストレージエンジンによって保証されます。
メッセージの取得
メッセージキューの先頭にあるメッセージを取得するには、以下の手順をたどります。
- 先頭のメッセージをロックする
- ロックしたメッセージのIDを取得する
- ロックしたメッセージの内容を取得する
- ロックしたメッセージを削除する
一つ一つ解説します。
1. 先頭のメッセージをロックする
メッセージを処理するクライアントが複数存在する場合、ロックを行わないと1つのメッセージを2つのクライアントが同時に取得してしまう事が起こりえます。
そこで、今から処理を始めるメッセージをロックする事で、他のクライアントからは利用できないようにします。
以下の SQL を実行します。
UPDATE test_queue
SET id = LAST_INSERT_ID(id),
locked_until = NOW() + INTERVAL 10 SECOND
WHERE locked_until < NOW() ORDER BY id LIMIT 1;
なぜこの SQL が先頭のメッセージをロックする事になるのか考えてみましょう。
まず
id = LAST_INSERT_ID(id)
という部分についてですが、これはロックしたメッセージのIDを取得するためのものです。後で解説します。
locked_until = NOW() + INTERVAL 10 SECOND
は、locked_until カラムに現在時刻から10秒後の時刻を設定しています。
WHERE locked_until < NOW()
は、locked_until カラムが現在時刻より前のものを取得する事を表しています。
ORDER BY id LIMIT 1
で、id 昇順 (つまり追加された順) に並べ、先頭1件を取得しています。
locked_until カラムに10秒後の時刻を設定すると、他のクライアントは10秒間、WHERE 条件によりこのメッセージを SELECT しなくなります。このようにして、ロック機構を実現しています。
仮に、クライアントが突然終了しても、10秒後にはロックが解除され、他のクライアントによって処理される事になります。
2. ロックしたメッセージのIDを取得する
以下の SQL を実行します。
SELECT LAST_INSERT_ID();
LAST_INSERT_ID 関数 は、引数付きで呼び出された場合、内部に引数を保存した上で、引数をそのまま返します。引数なしで呼び出された場合、最後に保存された内部の引数を返します。
メッセージをロックした際に id = LAST_INSERT_ID(id) という指定を行っていましたが、そのお陰でメッセージのIDを取得する事ができます。
また、MySQL のクライアントライブラリによっては、この取得を関数で行う事ができます。
例として PHP では mysql_insert_id 関数 や PDO::lastInsertId メソッド を利用する事で取得できます。
3. ロックしたメッセージの内容を取得する
得られたメッセージのIDを使って、普通に SELECT します。
SELECT data FROM test_queue WHERE id = ?;
4. ロックしたメッセージを削除する
得られたメッセージのIDを使って、普通に DELETE します。
DELETE FROM test_queue WHERE id = ?;
通常は、この時点でレコードが削除されるため、他のクライアントからは参照できないままですが、仮にレコードが削除される前にプロセスが終了してしまっても、10秒後には新たなクライアントが処理を開始します。
以上で、メッセージキューを実装できました。
PHP での実装例
上記を元に PHP でメッセージキューを実装した例を以下で公開しています。
http://github.com/kotas/myqueue
メッセージキューの実装である MyQueue クラスのURLは以下です。
http://github.com/kotas/myqueue/blob/master/MyQueue.php
ベンチマーク
ニコニコ動画で使用している典型的な MySQL サーバー上で 1000 個のメッセージを追加(push)/取得(pop)した場合、以下のようになりました。
push
Total: 0.162686 sec.
QPS: 6146.815289 query/sec.
SPQ: 0.000163 sec/query.
pop
Total: 1.719178 sec.
QPS: 581.673348 query/sec.
SPQ: 0.001719 sec/query.
追加(push) は単なる INSERT なので高速ですが、取得は UPDATE + SELECT + DELETE という3つのクエリが含まれるため、やや低速になります(581メッセージ/秒)。
なお、ベンチマークのコードは以下にあります。
http://github.com/kotas/myqueue/blob/master/benchmark.php
おわりに
MySQL を使ったお手軽なメッセージキューの実装方法を紹介しました。
なお、この記事中に含まれるコードは全て The MIT License です。
Enjoy!
このエントリでは Ruby on Rails と MySQL を使って日本語の全文検索を行う方法を記述する。Ruby on Rails のバージョンは 2.0.2、MySQL のバージョンは 5.0.67、Tritonn のバージョンは 1.0.12、Hyper Estraier のバージョンは 1.4.10 を使用した。サンプルの文章データとして、あらゆる日本人にとって極めて身近な著作権切れ文章である『ドグラ・マグラ』と『黒死館殺人事件』を利用した。処理のために整形したデータは本エントリに添付しておく。またデータベースへアクセスするコードではマイグレーションを除きできるだけベンチマークを取るようにし、その結果は本エントリの最後に記載する。
ページネーション
Rails でページネーションを実現する will_paginate という plugin は ActiveRecord に標準でついているような検索メソッドには対応しているものの、全文検索用 plugin による検索のように特殊なメソッドを使う検索結果のページネーションには対応していない。しかし will_paginate/lib/will_paginate/finder.rb を見ると、手軽に独自のやり方を追加できることがわかる。acts_as_tritonn の find_fulltext に対応したページネーションを実装すればよい。
まずは will_paginate をインストールする。公式の Wiki には「The gem is preferred method of installation; if you have the plugin in "vendor/plugins/will_paginate/" directory, it may be best to remove it and simply configure your application to load the gem.
」とあるので次のようにして gem からインストールする:
gem sources -a http://gems.github.com
gem install mislav-will_paginate
今後は will_paginate をインストールしているものとして話を進める。全文検索におけるページネーションへの対応は各 plugin の項で説明する。
全文検索を行うことのできる二つの plugin
MySQL で日本語の全文検索を行うには二つのメジャーな方法がある、Tritonn を使う場合と Hyper Estraier を使う場合だ。どちらの場合も SQL で全文検索専用の構文を使わなけらず、素の Rails からではマイグレーションや検索などで多少見栄えが悪い。それを解決するために、Tritonn の場合は acts_as_tritonn、Hyper Estraier の場合は acts_as_searchable という plugin が存在する。
acts_as_triton
その名の通り Rails から Tritonn を使うための plugin。次のようにしてインストールする:
script/plugin install http://ryu.rubyforge.org/svn/acts_as_tritonn
更に、Tritonn の SourceForge.JP プロジェクトページなどから Tritonn のバイナリパッケージをインストールし、起動しておくこと。
データベースの準備
mysql コマンドを実行し、次のクエリでデータベースを作成する:
CREATE DATABASE tritonn_development DEFAULT CHARACTER SET utf8;
config/database.yml の development を次のように編集する:
development:
adapter: mysql
database: tritonn_development
username: tritonn
password:
host: localhost
encoding: utf8
timeout: 5000
各種設定は各自の環境に合わせること。
次にデータベースを定義するためマイグレーションを書くのだが、ここでひとつ問題がある。activerecord-2.0.2/lib/active_record/connection_adapters/mysql_adapter.rb を見ると、create_table は次のようになっている:
def create_table(name, options = {}) #:nodoc:
super(name, {:options => "ENGINE=InnoDB"}.merge(options))
end
ストレージエンジンが InnoDB になるようベタ書きされている。このため ActiveRecord のマイグレーションでは、MySQL の設定がどうなっていようがデフォルトでは InnoDB になってしまう。
activerecord-2.0.2/lib/active_record/fixtures.rb の RDoc には次のように書かれている:
# When *not* to use transactional fixtures: (略) # 2. Your database does not support transactions. Every Active Record database supports transactions except MySQL MyISAM. # Use InnoDB, MaxDB, or NDB instead.
つまり、transactional fixtures のためにトランザクションの無い MyISAM を避けデフォルトで InnoDB を使うようになっているのだろう。
しかし Tritonn では MyISAM を使う必要がある。デフォルトで InnoDB になってしまう設定を上書きするには、create_table に :options => "ENGINE = MYISAM" とすればよい。
まずモデルを作成する:
script/generate model paragraph
db/migrate/001_create_paragraphs.rb を編集する:
class CreateParagraphs < ActiveRecord::Migration
def self.up
create_table :paragraphs, :options => "ENGINE = MYISAM" do |t|
t.column :body, :text, :null => false
end
end
def self.down
drop_table :paragraphs
end
end
app/models/paragraph.rb を acts_as_tritonn に対応させる:
class Paragraph < ActiveRecord::Base
acts_as_tritonn
end
次にこのモデルに全文検索のインデックスを張る。次のコマンドを実行する:
script/generate migration AddIndex
db/migrate/002_add_index.rb を編集する:
class AddIndex < ActiveRecord::Migration
def self.up
add_index :paragraphs, [:body], :fulltext => "NGRAM"
end
def self.down
remove_index :paragraphs, :body
end
end
最後にマイグレーションを実行する:
rake db:migrate
あとはそこにデータを入れるだけで自動的に全文検索用インデックスが更新される。
データの投入
サンプル文章を改行区切りで記述してあるファイル text.txt を Rails アプリケーションディレクトリ直下に置き、script/runner で動かすことのできる次のようなファイル、script/add_paragraphs.rb を用意する:
# -*- coding: utf-8 -*-
require 'benchmark'
puts Benchmark::CAPTION
bm = Benchmark.measure do
open "text.txt" do |file|
while line = file.gets
line.chomp!
paragraph = Paragraph.new()
paragraph.body = line
paragraph.save!
end
end
end
puts bm
そして次のようにコマンドを実行する:
script/runner script/add_paragraphs.rb
これで text.txt の中身を一行ずつ全文検索データベースに投入することができる。
データの検索
挿入したデータを検索する script/search_paragraphs.rb を準備する:
# -*- coding: utf-8 -*-
require 'benchmark'
Benchmark.bm do |x|
x.report do
paragraphs = Paragraph.find_fulltext({:body => "人間"})
end
x.report do
paragraphs = Paragraph.find_fulltext({:body => "殺し"})
end
x.report do
paragraphs = Paragraph.find_fulltext({:body => "残酷"})
end
x.report do
paragraphs = Paragraph.find_fulltext({:body => "人間 殺し 残酷"})
end
end
検索する文字列にはサンプルデータ中で一般的な単語を使用した。次のコマンドを実行することでこのスクリプトを呼び出すことができる:
script/runner script/search_paragraphs.rb
ページネーション
まず config/environment.rb の最後へ次の一行を追加すること:
require 'will_paginate'
find_fulltext をページネーションに対応させるため、app/controllers/application.rb の最後へ次のコードを追加する:
module WillPaginate
module Finder
module ClassMethods
def paginate_by_find_fulltext(query, options)
page, per_page, total_entries = wp_parse_options(options)
WillPaginate::Collection.create(page, per_page, total_entries) do |pager|
options.delete(:page)
options.delete(:per_page)
count_options = options.dup
count_options.delete(:select)
unless pager.total_entries
pager.total_entries = count_fulltext(query, count_options)
end
options[:limit] = per_page.to_i
options[:offset] = (page.to_i - 1) * per_page.to_i
pager.replace find_fulltext(query, options)
end
end
end
end
end
見た通り、WillPaginate::Collection.create を呼び、渡したブロックの中で pager.replace に検索結果を、pager.total_entries に結果件数を代入すればよい。
これで paginate_by_find_fulltext を使ってページネーションができるようになった。実際にページネーションを行うサンプルを以下に示す。
app/controllers/test_controller.rb
class TestController < ApplicationController
def search
@search_word = params[:search_word].to_s
if @search_word != ''
@paragraphs = Paragraph.paginate_by_find_fulltext(
{:body => @search_word},
:page => params[:page],
:per_page => 10,
:order => "id"
)
end
end
end
app/views/test/search.html.erb
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<title>検索</title>
</head>
<body>
<% form_tag({:action => "search"}, {:onsubmit => "if (this.search_word.value.strip() != '') location.href='/'+encodeURIComponent(this.search_word.value.strip()).replace(/%20/g, '+').replace(/%2F/g, '%252F'); return false;", :method => "get"}) do %>
<p>
<%= text_field_tag "search_word", h(@search_word) %>
<%= submit_tag "検索", :class => "submit" %>
</p>
<% end %>
<% if defined? @paragraphs %>
<ul>
<% @paragraphs.each do |paragraph| %>
<li><%= h(paragraph.body) %></li>
<% end %>
</ul>
<%= will_paginate @paragraphs, :prev_label => 'Prev', :next_label => 'Next' %>
<% end %>
</body>
</html>
config/routes.rb を以下のように書き換える:
ActionController::Routing::Routes.draw do |map|
map.connect '/search', :controller => 'test', :action => 'search'
map.connect '/search/*search_word', :controller => 'test', :action => 'search'
end
あとは script/server で起動し http://localhost:3000/search/ にアクセスし検索を行えばよい。あらかじめ script/add_paragraphs.rb でデータを投入しておけば、多くの検索結果がある場合にきちんとページネーションが行われているのを見ることができる。
acts_as_searchable
Rails から Hyper Estraier を使っての全文検索を提供する plugin。次のようにしてインストールする:
ruby script/plugin source svn://poocs.net/plugins/trunk
ruby script/plugin install acts_as_searchable
また Hyper Estraier のバイナリパッケージも入手しておくこと。
データベースの準備
mysql コマンドを実行し、次のクエリでデータベースを作成する:
CREATE DATABASE hyperestraier_development DEFAULT CHARACTER SET utf8;
config/database.yml の development を次のように編集する:
development:
adapter: mysql
database: hyperestraier_development
username: root
password:
host: localhost
encoding: utf8
timeout: 5000
estraier:
host: localhost
user: admin
password: admin
port: 1978
node: development
各種設定は各自の環境に合わせること。
次に Hyaper Estraier のバイナリのあるディレクトリへ PATH を通した状態で Hyper Estraier のデータを置くディレクトリへ移動し、次のコマンドを実行する:
estmaster init test
Hyper Estraier を起動する:
estmaster start test
ウェブブラウザで http://localhost:1978/ を開き、administration -> Manage Nodes の順で開き、二つのテキスト入力欄を「development」と「node for development」で埋め、create を押す。これで全文検索のためのノードが生成された。
モデルを作成する:
script/generate model paragraph
db/migrate/001_create_paragraphs.rb を編集する:
class CreateParagraphs < ActiveRecord::Migration
def self.up
create_table :paragraphs do |t|
t.column :body, :text, :null => false
end
end
def self.down
drop_table :paragraphs
end
end
Hyper Estraier は MySQL とは別に存在するため、MySQL へのマイグレーションの際には特別なことをする必要が無い。
app/models/paragraph.rb を acts_as_searchable に対応させる:
class Paragraph < ActiveRecord::Base
acts_as_searchable :searchable_fields => [:body]
end
これで body カラムに全文検索インデックスが張られる。
マイグレーションを実行する:
rake db:migrate
データの投入
acts_as_tritonn の時と同様に、サンプル文章を改行区切りで記述してあるファイル text.txt を Rails アプリケーションディレクトリ直下に置き、script/runner で動かすことのできる次のようなファイル、script/add_paragraphs.rb を用意する:
# -*- coding: utf-8 -*-
require 'benchmark'
require 'acts_as_searchable'
puts Benchmark::CAPTION
bm = Benchmark.measure do
open "text.txt" do |file|
while line = file.gets
line.chomp!
paragraph = Paragraph.new()
paragraph.body = line
paragraph.save!
end
end
end
puts bm
save! 時の全文検索インデックスの更新は plugin によって隠蔽されているため、acts_as_tritonn の時と全く同じソースコードを使うことができる。
コマンドの実行も同様に行う:
script/runner script/add_paragraphs.rb
データの検索
挿入したデータを検索する script/search_paragraphs.rb を準備する:
# -*- coding: utf-8 -*-
require 'benchmark'
Benchmark.bm do |x|
x.report do
paragraphs = Paragraph.fulltext_search("人間")
end
x.report do
paragraphs = Paragraph.fulltext_search("殺し")
end
x.report do
paragraphs = Paragraph.fulltext_search("残酷")
end
x.report do
paragraphs = Paragraph.fulltext_search("人間 AND 殺し AND 残酷")
end
end
acts_as_tritonn の場合と構文が大きく違うことに注意。スクリプトの呼び出しは変わらない:
script/runner script/search_paragraphs.rb
ページネーション
まず config/environment.rb の最後へ次の一行を追加すること:
require 'will_paginate'
fulltext_seach をページネーションに対応させる plugin があるので、それを利用する:
script/plugin install http://small-plugins.googlecode.com/svn/trunk/will_paginate_acts_as_searchable/
この plugin をインストールすることによって使えるようになる paginate_by_fulltext_search を使ったページネーションを行うサンプルを以下に示す。
app/controllers/test_controller.rb
class TestController < ApplicationController
def search
@search_word = params[:search_word].to_s
if @search_word != ''
@paragraphs = Paragraph.paginate_by_fulltext_search(
@search_word,
:page => params[:page],
:per_page => 10,
:order => "id"
)
end
end
end
app/views/test/search.html.erb
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Script-Type" content="text/javascript" />
<title>検索</title>
</head>
<body>
<% form_tag({:action => "search"}, {:onsubmit => "if (this.search_word.value.strip() != '') location.href='/'+encodeURIComponent(this.search_word.value.strip()).replace(/%20/g, '+').replace(/%2F/g, '%252F'); return false;", :method => "get"}) do %>
<p>
<%= text_field_tag "search_word", h(@search_word) %>
<%= submit_tag "検索", :class => "submit" %>
</p>
<% end %>
<% if defined? @paragraphs %>
<ul>
<% @paragraphs.each do |paragraph| %>
<li><%= h(paragraph.body) %></li>
<% end %>
</ul>
<%= will_paginate @paragraphs, :prev_label => 'Prev', :next_label => 'Next' %>
<% end %>
</body>
</html>
config/routes.rb を以下のように書き換える:
ActionController::Routing::Routes.draw do |map|
map.connect '/search', :controller => 'test', :action => 'search'
map.connect '/search/*search_word', :controller => 'test', :action => 'search'
end
Hyper Estraier を起動してから script/add_paragraphs.rb でデータを投入し、次に script/server で Rails アプリケーションを起動し http://localhost:3000/search/ にアクセスし検索を行えば、ページネーションが動作していることを確認することができる。
ベンチマーク結果
まず念のために言っておくと、これはそれぞれの plugin を通しての結果なので Tritonn 及び Hyper Estraier が持つ本来のパフォーマンスとは限らない。plugin を使わなくてもいいというのなら Tritonn や Hyper Estraier の複雑な構文をそのまま Rails で使うことで更に高速化する余地は残されている。
以下は、ディスク I/O を最小限にするため、ディスク上のファイルへあらかじめアクセスして HDD 内部や OS 側でのキャッシュを効かせた状態で計測している。
search_paragraphs.rb の動作結果:
acts_as_tritonn
user system total real
0.063000 0.031000 0.094000 ( 0.110000)
0.015000 0.000000 0.015000 ( 0.015000)
0.000000 0.000000 0.000000 ( 0.000000)
0.000000 0.000000 0.000000 ( 0.000000)
acts_as_searchable
user system total real
0.000000 0.000000 0.000000 ( 0.016000)
0.000000 0.000000 0.000000 ( 0.016000)
0.000000 0.000000 0.000000 ( 0.015000)
0.000000 0.000000 0.000000 ( 0.000000)
一番最初だけ 4 倍の差で acts_as_seachable の方が速い。しかし残りのうち二つでは acts_as_tritonn の方が速かったりするので、実運用上の様々な検索を実行した場合にはもっと違う、複雑な結果が出ると思う。実際に使う場面に応じて必要な計測を行い、適したものを使うべきだろう。
add_paragraphs.rb の動作結果:
acts_as_tritonn
user system total real
4.328000 1.422000 5.750000 ( 8.921000)
acts_as_searchable
user system total real
10.844000 4.891000 15.735000 (168.829000)
ちょっと見過ごせない程の極端な差がついた。acts_as_seachable で save! の時に毎回インデックスを更新していることが問題になっているようだ。Hyper Estraier の User's Guide にはこうある。
可用性の確保
インデックスを更新している最中にはロックがかかるので、そのインデックスを使った検索はその間はできなくなります。検索システムとしては、その間は停止時間ということになります。それを避けるためには、インデックスのコピーに対して更新を処理を行い、完了したらオリジナルと入れ換えるようにするとよいでしょう。
Hyper Estraier では元々大規模な利用においてリアルタイムでインデックスを更新することを考えていないようだ。従って acts_as_seachable の実装に問題があるということになる。簡単に全文検索インデックスを付けたい場合に acts_as_searchable は使えるが、現状のままではある程度の更新が発生する大規模サイトに使うのは難しい。acts_as_searchable から更新時のリアルタイムインデックス更新機能を削り、任意のタイミングでインデックスを更新するように改造する必要がある。
acts_as_tritonn の場合にはこのような手間はよほど大規模にならない限り必要無いと思われるため、そのまま使うことができる。
text.zip
弊社でも毎年恒例となりつつある技術系のインターンシップが始まりました。
今年のインターンシップに参加される学生さんは4名で、それぞれ2名づつ2チームに分かれ、ホストとなる社員とともに、研究開発本部のテーマに沿ったプロダクト開発を約1ヶ月にわたってフルタイムで行っていただきます。
今年のテーマは、やはりニコニコ動画関連です。
インターンの最後には社内で成果発表を行っていただきますし、その成果によっては世にでる可能性も十分にあります。
参加者のみなさんにはこの機会にネット・エンターテインメントの開発サイド、仕事としてのソフトウェア開発、多くのエンドユーザ様へのプロダクト・アウトについて経験していただけることを期待しています。
独立行政法人 情報処理推進機構(IPA)/財団法人 日本情報処理開発協会(JIPDEC)が主催となって8月13日〜8月17日にかけて、「セキュリティ&プログラミングキャンプ2008」が開催されています。
そのプログラムの一部として、本日、プログラミングキャンプ参加者のみなさんが企業見学としてドワンゴまで来ていただきました。
そこでは、ドワンゴの成り立ちやビジネスの経緯、開発現場の実際や、サービスができるまでのステップなどをお話させていただきました。
またその後、社内見学ツアーと、ニコニコ動画を作った戀塚を含むドワンゴのエンジニアとの交流会も実施しました。
プログラミングキャンプ参加者の方は14歳〜22歳と若い方ばかりで、交流会に参加したエンジニアも参加者の方々のプログラミングを学ぼうという強い気持ちに刺激を受けたようです。
参加者のみなさんにも、弊社のサービス開発の実際や、エンジニアの文化などにふれていただけたかと思います。
この若い人たちのなかから、将来の「達人プログラマー」が沢山輩出されることでしょう。期待しています。
弊社エンジニア、戀塚昭彦が Adobe Max Japan 2007 における講演で使用した資料を公開します。
- ニコニコ動画とFlash (swf 2.0MB)
講演をお聞きくださった皆様に感謝いたします。
また先日開催されたイベント ITpro Challenge! での動画を ITpro 様に公開していただきました。
講演資料はこちらで公開しております。
- ニコニコ動画の創りかた 戀塚昭彦 (swf)
ITpro様、ありがとうございました。
Files
日経BP社様のイベント「ITpro Challenge!」 (2007/9/7) で用いた発表用資料です。

最近のコメント