$ cat Vagrantfile
VAGRANTFILE_API_VERSION = '2'

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = 'chef/centos-7.0'

  config.vm.network 'private_network', ip: '192.168.33.10'
end
$ vagrant up
Bringing machine 'default' up with 'vmware_fusion' provider...
==> default: Cloning VMware VM: 'chef/centos-7.0'. This can take some time...
==> default: Checking if box 'chef/centos-7.0' is up to date...
==> default: Verifying vmnet devices are healthy...
==> default: Preparing network adapters...
==> default: Starting the VMware VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 192.168.101.153:22
    default: SSH username: vagrant
    default: SSH auth method: private key
==> default: Machine booted and ready!
==> default: Checking for host entries
==> default: Forwarding ports...
    default: -- 22 => 2222
==> default: Configuring network adapters within the VM...
The following SSH command responded with a non-zero exit status.
Vagrant assumes that this means the command failed!

/sbin/ifup eth1

Stdout from the command:

ERROR    : [/etc/sysconfig/network-scripts/ifup-eth] Device eth1 does not seem to be present, delaying initialization.


Stderr from the command:
$ vagrant ssh
Last login: Tue Jul 22 03:39:40 2014 from 172.16.230.1
[vagrant@localhost ~]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:d7:aa:94 brd ff:ff:ff:ff:ff:ff
    inet 192.168.101.153/24 brd 192.168.101.255 scope global dynamic ens32
       valid_lft 1636sec preferred_lft 1636sec
    inet6 fe80::20c:29ff:fed7:aa94/64 scope link
       valid_lft forever preferred_lft forever
3: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:d7:aa:9e brd ff:ff:ff:ff:ff:ff
    inet 192.168.33.132/24 brd 192.168.33.255 scope global dynamic ens33
       valid_lft 1636sec preferred_lft 1636sec
    inet6 fe80::20c:29ff:fed7:aa9e/64 scope link
       valid_lft forever preferred_lft forever

provider が VirtualBox だと問題ないのに……

プロジェクトマネジメントツール

the-pineapple-blog:

いま以下のツールをグループで使っている.

  • Asana
  • Basecamp
  • ChatWork
  • GitHub

他にコミュニケーション用として以下のツールを使っている.

  • Facebook
  • Google Hangout
  • LINE
  • Skype
  • SMS/MMS/iMessage
  • メール
  • 電話

ファイルの共有には以下のツールも使う.

  • Dropbox
  • Google Drive

個人のタスクは OmniFocus で管理している.

明らかにクレイジーだ.なんとかしたい.

まとめたい気持ちは分かる

Riak Search (Yokozuna) で日本語の全文検索を行う方法

はじめに

下記のようにデータを保存しても、全文検索を行うことができない。なぜかと言うと、Solr 側に全文検索の対象とするフィールドを教えてあげる必要があるからである。

$ rails c
Loading development environment (Rails 4.1.5)
[1] pry(main)> client = Riak::Client.new
=> #<Riak::Client [#<Node 127.0.0.1:8087>]>
[2] pry(main)> bucket = client.bucket 'artists'
=> #<Riak::Bucket {artists}>
[3] pry(main)> client.create_search_index 'artists'
=> true
[4] pry(main)> client.set_bucket_props bucket, { search_index: 'artists' }
=> true
[5] pry(main)> casiopea = bucket.new 'casiopea'
=> #<Riak::RObject {artists,casiopea} [#<Riak::RContent [application/json]:nil>]>
[6] pry(main)> casiopea.data = { description: 'カシオペア (Casiopea) は、日本のフュージョンバンド。' }
=> {:description=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}
[7] pry(main)> casiopea.store
=> #<Riak::RObject {artists,casiopea} [#<Riak::RContent [application/json]:{"description"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}>]>
[8] pry(main)> client.search('artists', '*:*')
=> {"max_score"=>1.0,
 "num_found"=>1,
 "docs"=>[{"score"=>"1.00000000000000000000e+00", "_yz_rb"=>"artists", "_yz_rt"=>"default", "_yz_rk"=>"casiopea", "_yz_id"=>"1*default*artists*casiopea*27"}]}
[9] pry(main)> client.search('artists', 'description:日本')
=> {"max_score"=>0.0, "num_found"=>0, "docs"=>[]}

これを解決するためには

  • 全文検索の対象とするフィールドを定義したスキーマを作成する
  • デフォルトスキーマに定義されているダイナミックフィールドを使う

が考えられる。今回は後者のダイナミックフィールドを使う方法について説明する。

ダイナミックフィールドを使う方法

デフォルトスキーマのダイナミックフィールドは下記のように定義されている。

<dynamicField name="*_cjk" type="text_cjk" indexed="true" stored="true" multiValued="true"/>
<dynamicField name="*_ja" type="text_ja" indexed="true" stored="true" multiValued="true"/>

*_cjk は bi-gram、*_ja は形態素解析で全文検索を行うことができる。

bi-gram で全文検索してみる

全文検索の対象するフィールド名の終わりを _cjk とすることにより bi-gram で全文検索できるようになる。

[10] pry(main)> casiopea = bucket.get_or_new 'casiopea'
=> #<Riak::RObject {artists,casiopea} [#<Riak::RContent [application/json]:{"description_ja"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}>]>
[11] pry(main)> casiopea.data = { description_cjk: 'カシオペア (Casiopea) は、日本のフュージョンバンド。' }
=> {:description_cjk=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}
[12] pry(main)> casiopea.store
=> #<Riak::RObject {artists,casiopea} [#<Riak::RContent [application/json]:{"description_cjk"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}>]>
[13] pry(main)> client.search('artists', 'description_cjk:日本')
=> {"max_score"=>0.15581955015659332,
 "num_found"=>1,
 "docs"=>
  [{"score"=>"1.55819550000000001111e-01",
    "_yz_rb"=>"artists",
    "_yz_rt"=>"default",
    "_yz_rk"=>"casiopea",
    "_yz_id"=>"1*default*artists*casiopea*28",
    "description_cjk"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}]}

形態素解析で全文検索してみる

全文検索の対象するフィールド名の終わりを _ja とすることにより形態素解析で全文検索できるようになる。

[14] pry(main)> casiopea = bucket.get_or_new 'casiopea'
=> #<Riak::RObject {artists,casiopea} [#<Riak::RContent [application/json]:{"description"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}>]>
[15] pry(main)> casiopea.data = { description_ja: 'カシオペア (Casiopea) は、日本のフュージョンバンド。' }
=> {:description_ja=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}
[16] pry(main)> casiopea.store
=> #<Riak::RObject {artists,casiopea} [#<Riak::RContent [application/json]:{"description_ja"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}>]>
[17] pry(main)> client.search('artists', 'description_ja:日本')
=> {"max_score"=>0.31163910031318665,
 "num_found"=>1,
 "docs"=>
  [{"score"=>"3.11639100000000002222e-01",
    "_yz_rb"=>"artists",
    "_yz_rt"=>"default",
    "_yz_rk"=>"casiopea",
    "_yz_id"=>"1*default*artists*casiopea*29",
    "description_ja"=>"カシオペア (Casiopea) は、日本のフュージョンバンド。"}]}

Data Types で全文検索を行うには?

Riak 2.0 から導入された Data Types で全文検索を行うにはスキーマを作成する方法しかない。

デフォルトスキーマでは下記のように定義されている。

<!-- Riak datatypes default fields-->
<field name="counter" type="int"    indexed="true" stored="true" multiValued="false" />
<field name="set"     type="string" indexed="true" stored="false" multiValued="true" />
<!-- Riak datatypes embedded fields -->
<dynamicField name="*_flag"     type="boolean" indexed="true" stored="true" multiValued="false" />
<dynamicField name="*_counter"  type="int"     indexed="true" stored="true" multiValued="false" />
<dynamicField name="*_register" type="string"  indexed="true" stored="true" multiValued="false" />
<dynamicField name="*_set"      type="string"  indexed="true" stored="false" multiValued="true" />

Maps で文字列を保存する registers は、string 型で定義されているためである。そのため、下記のようなフィールド定義したスキーマを作成する必要がある。

<field name="description_register" type="text_ja" indexed="true" stored="true" multiValued="true" />
男3人てパンケーキ! (恵比寿 カフェ アクイーユ Accueil)

男3人てパンケーキ! (恵比寿 カフェ アクイーユ Accueil)

the-pineapple-blog:

Appleすげー.

ベータ版のXcodeを立ち上げるとライセンスアグリーメントのダイアログが出てくるのは予想の範疇なんだけれど,まさかclangをコマンドラインで叩いても同じことさせられる(しかもコマンドラインで解決できる)とは思わなかった.