コードジガー

色々と書くと思います

リレーショナル・データベースの「関係」にまつわるオハナシ

言葉

関係データベース、RDBMS

話。
「参照整合性みたいな感じで関係を持っているからRDBMSと言うんだよ」

一理あり、一見筋も通っていそうだけど、ほんとに?

SQLの習慣では、リレーションを「テーブル (table)」、属性を「列(column)」、タプルを「行(row)」と呼ぶ。

数学的なリレーションの話
RDBMSはリレーション(テーブル)を使っているから、そういう名前がつけられたものなんだけど、そもそもリレーションってタプル(行)の集合だから、タプルは属性を原子的な値に写像するものなのです。
例えば、

{name: 'Takaya Hashiguchi', p.age: 25}

属性は、属性ヘッダ行(つまり列)で定義されてて、ドメインや制約型がついてることもある。
例えば、

{name: string, age: int}

これがリレーショナルな構造を表現する要点。

RDBMS、リレーショナル・データベース
名前は数学的だけど、実装は割りと実用的。
なぜ、数学的な話を持ちだしたかというと、リレーショナル・データベースが数学的な「関係」であることを強調したいから。外部キーを使って他のテーブルと「関係」を持つからじゃない。
そうした制約は関係のない話。

リレーショナル・データベースは、数学的な側面があんまり表に出ていない。
出さないようにしている?

でも、ユーザは強力なクエリを表現できるし、システムも規定のパターンで最適化できるから、リレーショナルモデルの力は数学によるところが大っきいと思う。

RDBMS集合論から派生した関係代数をもとにして構築されてて、射影、選択、結合(デカルト積、つまりJOIN)などを組み合わせたもの。

{\large \pi \tiny name(\large\sigma \tiny age= \omega(\large\rho \tiny x(\tiny People)))}

{\large \pi \tiny name} nameだけを返す、つまり -> SELECT x.name
{(\large\rho \tiny x(\tiny People)))} People を x に改名する、つまり -> FROM People x
{\large\sigma \tiny age= \omega} age が nullのところを選択する、つまり -> WHERE x.age IS NULL

続きを読む

Solr4.0のJapaneseTokenizerFactory ( kuromoji ) で記号や特殊文字が捨てられないようにする方法

Solr4.0 の schema.xml(sample) では 以下のようになっていて、このまま text_jaを使っても記号特殊記号をインデックス化してくれない
このまま使うと記号や特殊記号が消えてしまう
lucene-gosenはdefaultで記号を拾います

schema.xml

<fieldType name="text_ja" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
  <analyzer>
    <tokenizer class="solr.JapaneseTokenizerFactory" mode="search"/>
  </analyzer>
</fieldType>

f:id:takaya1219:20121121151301p:plain

しかし、kuromojiのサイトではキチンと解析できていることがわかる
つまり、できるはず
f:id:takaya1219:20121121145658p:plain
ということでソース追ってみたら discardPunctuationという設定があった!

JapaneseTokenizerFactory に対して discardPunctuation="false"を与えると記号や特殊記号を拾ってくれるようになる
※ default true
ただし、Solr3.6系ではソースコード上では実装されているが schema.xmlから設定することができない
もし、やるならソースコードを書き換える必要がある

schema.xml

<fieldType name="text_ja" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
  <analyzer>
    <tokenizer class="solr.JapaneseTokenizerFactory" mode="search" 
      discardPunctuation="false" />
  </analyzer>
</fieldType>

f:id:takaya1219:20121121151315p:plain

"★","♂","☆" 等の記号が拾われていることがわかる!

Centos6.x系にNTPサーバを構築する

NTPサーバをインストールする

[root@jigoku ~]# yum install -y ntp


NTPサーバの設定を変更する
RFC4330によると,NTPサーバはホスト名で設定することが推奨されている
1.NTPサーバの設定ファイルを編集する(/etc/ntp.conf)

2.ローカルからの時刻同期を許可

3.時刻同期先のNTPサーバを変更
ntp.nict.jp は,日本標準時を供給している独立行政法人情報通信研究機構(NICT)を指しており,精度は日本標準時に対して10ナノ秒以内らしい.
ntp.nict.jp を指定すると,4台のNTPサーバをラウンドロビンで参照する.
stratumは1であり,個人利用を認めている.

ntp.jst.mfeed.ad.jp はインターネットマルチフィードによるNTPサービス.
インターネットマルチフィードはIPS間を相互接続するJANAPを運用しているため,国内のISPと直接接続しているらしい.
ntp.jst.mfeed.ad.jp を指定すると,3台のNTPサーバをラウンドロビンで参照する.
stratumは2.

ntp.ring.gr.jp を指定すると複数のNTPサーバをラウンドロビンで参照する.

[root@jigoku ~]# vi /etc/ntp.conf

# 2.ローカルからの時刻同期を許可
# Hosts on local network are less restricted.
# restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
↓
restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap

# 3.時刻同期先のNTPサーバを変更
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
# server 0.centos.pool.ntp.org
# server 1.centos.pool.ntp.org
# server 2.centos.pool.ntp.org
↓
server ntp.nict.jp
server ntp.jst.mfeed.ad.jp
server ntp.ring.gr.jp


NTPサーバを起動する
1.ntpdateで手動でサーバの時刻を合わせる.大幅にズレているとNTPサーバを起動できない場合がある.

2./etc/rc.d/init.d/ntpd startでNTPサーバを起動する

3.chkconfig onで自動起動設定(--listで確認できる)

[root@jigoku ~]# ntpdate ntp.nict.jp
27 Jul 01:32:22 ntpdate[1817]: step time server 133.243.238.244 offset -302.827464 sec

[root@jigoku ~]# /etc/rc.d/init.d/ntpd start
ntpd を起動中:                                             [  OK  ]

[root@jigoku ~]# chkconfig ntpd on

[root@jigoku ~]# chkconfig --list ntpd
ntpd            0:off   1:off   2:on    3:on    4:on    5:on    6:off


NTPサーバの確認
NTPサーバと時刻同期中はサーバ名の前が空白
時刻同期が完了すると*や+が表示される

[root@jigoku ~]# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ntp-a3.nict.go. .NICT.           1 u   22   64    3    5.784   -0.579   0.473
 ntp1.jst.mfeed. 210.173.160.56   2 u   22   64    3    4.278   -0.248   0.525
 udon.nict.go.jp 103.1.106.69     2 u   21   64    3    7.154   -1.083   0.814

[root@jigoku ~]# ntpq -p
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
*ntp-a3.nict.go. .NICT.           1 u   60   64  377    5.718   -2.791   1.092
+ntp1.jst.mfeed. 210.173.160.56   2 u   62   64  377    4.064   -1.396   1.049
+udon.nict.go.jp 133.243.238.244  2 u   61   64  377    5.781   -2.626   0.947

ntpqの説明

' '(reject)     距離が遠くて捨てられたサーバー
'x'(falsetick) falseticker検査で捨てられたサーバー
'.'(excess)     参照サーバーが多くて捨てられたサーバー
'-'(outlyer)    クラスタリング検査で捨てられたサーバー
'+'(candidat)   接続テストに合格し、いつでも参照可能なサーバー
'#'(selected)   同期距離が遠いが参照可能なサーバー
'*'(sys.peer)   同期中であると宣言されたサーバー
'o'(pps.peer)   同期中であると宣言されたサーバー(同期はPPS信号から間接的に行なう。)

remote          リモート・サーバーのホスト名
refid           参照ID(不明の場合は、0.0.0.0)
st              stratum番号,サーバーが第何階層かを表します。
t               階層タイプ(l:local,u:unicast,m:multicast,b:broadcast)
when            最後のパケットを受け取ってからの時間(単位:秒)
poll            ポーリング間隔(単位:秒)
reach           到達可能なレジスタを(8進数表現)
delay           ポーリングインターバルの遅延見積もり(単位:ミリ秒)
offset          階層のオフセット(単位:ミリ秒)
disp            階層の分散(単位:ミリ秒)

CentOS 6.x系の初期設定

CentOS 6.x系をインストールするが終わったので、初期設定をしていきます
ここでは,一般ユーザを作成したり,rootになれる管理者ユーザを設定したり
環境に配慮したエコなインストール(minimal.isoによる最小構成)だったので
Baseパッケージなどの必要なパッケージ群をインストールしたりと,色々やります!

1. ユーザの作成

[root@jigoku ~]# useradd takaya
[root@jigoku ~]# passwd takaya
ユーザー takaya のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: 全ての認証トークンが正しく更新できました。

[root@jigoku ~]# su takaya
[takaya@jigoku root]$ su -
パスワード:
[root@jigoku ~]#


2. rootになれるユーザを制限する
※ root権限があると何でも出来てしまうので,基本は一般ユーザでログインしroot権限が必要な場合のみsuでrootになるようにする
takayaをrootになれる管理者とする場合

[root@jigoku ~]# usermod -G wheel takaya  # takayaを管理者用wheelグループに追加

[root@jigoku ~]# vi /etc/pam.d/su
#%PAM-1.0
#auth            required        pam_wheel.so use_uid
↓
#%PAM-1.0
auth            required        pam_wheel.so use_uid

管理者用一般ユーザからはrootになれて、管理者以外の一般ユーザからはrootになれないことを確認
[root@jigoku ~]# useradd twitter  # 一般ユーザtwitterを作成
[twitter@jigoku root]$ su root  # rootになろうと試みる(パスワードは一致していても違うと出力される)
パスワード:
su: パスワードが違います

[root@jigoku ~]# su takaya  # 管理者用一般ユーザになる
[takaya@jigoku root]$ su root  # rootになる
パスワード:
[root@jigoku ~]#


3. パッケージ管理の初期設定(yumの初期設定)

[root@jigoku ~]# yum -y update
Loaded plugins: fastestmirror, presto
Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os error was
14: PYCURL ERROR 6 - "Couldn't resolve host 'mirrorlist.centos.org'"
Error: Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again

# 名前解決まわりでのエラー

DHCPを有効にしているとIPv6との競合でこういう状況になる
もしくは単純にプロバイダーのDNSが落ちているか
なので、DNS2にGoogle Public DNSを指定し、IPv6を無効化する
[root@jigoku ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0
DNS2=8.8.8.8
IPV6INIT=no
USERCTL=no

[root@jigoku ~]# yum -y update
結構時間がかかる

# yum-cronをインストール
[root@jigoku ~]# yum -y install yum-cron
Complete!
[root@jigoku ~]# /etc/rc.d/init.d/yum-cron start
夜間 yum 更新の有効化中:                                   [  OK  ]
[root@jigoku ~]# chkconfig yum-cron on

# ベースパッケージ群と開発ツールパッケージ群をインストール
[root@jigoku ~]# yum -y groupinstall "Base" "Development tools"

CentOSのフルインストールディスク(ここCentOS-6.3-x86_64-bin-DVD1.iso と CentOS-6.3-x86_64-bin-DVD2.iso )だとOSのインストール時にインストールするパッケージを選べるのですが,今回は環境に配慮したエコなインストールを行ったので,必要なパッケージを別途インストールしています
具体的には、ここから適当なリポジトリを選んで指定したパッケージ群をインストールしています!

インストールしているパッケージ一覧を見るには以下のコマンドを叩きます

[root@jigoku ~]# rpm -qa --queryformat "%-40{GROUP}:%{NAME}-%{VERSION}-%{RELEASE}\n"  | sort
Applications/Archiving                  :cpio-2.10-10.el6
Applications/Archiving                  :tar-1.23-7.el6
Applications/Archiving                  :unzip-6.0-1.el6
Applications/Archiving                  :zip-3.0-1.el6

(略)

System Environment/Shells               :tcsh-6.17-19.el6_2
User Interface/Desktops                 :abrt-cli-2.0.8-6.el6.centos
User Interface/Desktops                 :abrt-tui-2.0.8-6.el6.centos
User Interface/Desktops                 :hicolor-icon-theme-0.11-1.1.el6
User Interface/Desktops                 :libreport-cli-2.0.9-5.el6.centos


4. SELinux を無効化する

# 手動でSELinuxの設定変更(再起動すると元に戻る)
[root@jigoku ~]# getenforce
Enforcing
[root@jigoku ~]# setenforce 0
[root@jigoku ~]# getenforce
Permissive

# SELinux設定ファイルを編集する
[root@jigoku ~]# vi /etc/sysconfig/selinux

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
# SELINUX=enforcing  # ←SELinuxを有効化
SELINUX=disabled   # ←SELinuxを無効化
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted

/etc/sysconfig/selinux では SELinux を SELINUXTYPE で指定されたセキュリティ・ポリシーをどういった状態(SELINUX)で起動するか という設定を行なっています.

ちなみに,SELINUXTYPEはセキュリティ・ポリシー(ポリシーセット)を指定します.targetedを指定するとhttpdなどの代表的なデーモンのみが制御対象となり,strictを指定すると全てのデーモンが制御対象になります.MLSを指定すると全てのデーモンにRBAC(role base access control)を追加したstrictよりも厳格な動作をします.また,SELINUXは状態(state)を指定します.enforcingを指定するとセキュリティ・ポリシーに反する動作を全て拒否します.permissiveはセキュリティ・ポリシーに反する動作に対し警告を行います.disabledはSELinuxを無効化します.

たまにSELinux無効化反対派と出会いますが,元々SELinuxは政府系とか金融系などの厳格なセキュリティ要求を満たすために設けられた機能です.政府機関や金融機関からの強い要望がない限りSELinuxは無効で大丈夫だと思います.守るべき情報資産価値よりSELinuxの運用保守コストが大きくなるケースが殆どです.

5. nkfコマンドをインストールする
日本語処理に必要不可欠なのでインストールしておきます

[root@jigoku ~]# yum -y install nkf


んー、色々忘れてる気がするけど終わり\(^o^)/

CentOS 6.x系をインストールする

社会へ出るため徳島から東京へ引っ越した
しかし,自宅サーバは in the ダンボール のまま,はやくも7月なう です

今日は海の日です
リア充達は海でアレコレやっているというのに、ボクは自宅サーバを復活させようとしている
明日は仕事だというのに…

POP a Home-Server from ダンボー

半年くらい動かしていなかった癖に自宅サーバ様は壊れてなかった(つまらん

CentOSのバージョンが5.6だった

時代は6.x系に突入しているというのに!!

そういえば,上長に「Linuxわかってない」って詰られたし,勉強の意味も込めて再インストールすることにします

1. まずCentOSをDLしてきます
Index of /Linux/centos/6/isos/x86_64からCentOS-6.3-x86_64-minimal.iso をDLします

最近だと最小構成インストール(minimal.iso)が用意されているんですね
しかも,330MBしかない!
まさしくECOですね!

2. CentOS-6.3-x86_64-minimal.isoをDVDに焼きます
330MBをDVD(4.7GB)に焼いていて、ECOじゃないっていうツッコミはスルーします
DVDメディアしか自宅になかったんです(;´Д`)
WindowsだとisoファイルをDVDに焼くためにリッピングソフトが必要なのですが,Macだと「ディスクユーティリティ.app」で簡単に焼けちゃいます

3. インストール
6.x系のインストール画面カッコいいですね!
f:id:takaya1219:20120716192303j:plain

インストール時の注意点として,地域設定時に「システムクロックでUTCを使用(S)」からチェックを外す
「インストール言語の選択」で "Japanese" を選択してていれば,使用するタイムゾーンは "アジア/東京" になっています.CentOSはntpdを利用して,世界標準時刻(GMTとかUTC)を発信しているNTPサーバに接続し,自動的に時刻調整を行うことができます.GMTと日本標準時刻(JST)では9時間の時差がありますので,OSをGMTのまま運用させると面倒が多くなります.従って,通常は自国との時差を計算してシステム動作の基準時刻を設定するわけです.CentOSインストール時のデフォルトでは「システムクロックでUTCを使用(S)」にチェックが入っていますが,運用上はGMTを用いる場合と大差ないです.ここでは素直にGMT基準の地域選択を利用するためにチェックを外しておきます.

4. インストールが完了したらネットワークの設定

[root@jigoku ~]# vi /etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE=eth0
BOOTPROTO=none
HWADDR=00:00:00:00:00:00
NM_CONTROLLED=yes
ONBOOT=yes
TYPE=Ethernet
UUID="xxxxxxxxxxxxxxxxx"
IPADDR=192.168.11.123
NETMASK=255.255.255.0
GATEWAY=192.168.11.1
DNS1=192.168.11.1

[root@jigoku ~]# /etc/rc.d/init.d/network restart
インターフェース eth0 を終了中:                            [  OK  ]
ループバックインターフェースを終了中                       [  OK  ]
ループバックインターフェイスを呼び込み中                   [  OK  ]
インターフェース eth0 を活性化中:                          [  OK  ]

なんか日本語化されている...気持悪い(´・ω・`)

Finagleハッカソンへ行ってきたっ! #finagle_hack

Scalaを始めて数ヶ月、より深くScalaを学ぶためにTwitter製RPCフレームワークであるFinagleで遊び倒そうの会へ参加してきました。
まったくのFinagle初心者の私でしたが、水島さん(@kmizu)のわかりやすい資料や中村さん(@gakuzzzz)の解説のお陰でFinagleは触って遊ぶことができました!
ありがとうございました(´∀`)
また、会場を提供してくださったTwitter Japanの山本裕介さん(@yusukey)にも良くしていただいて、至れり尽くせりでした!
f:id:takaya1219:20120618004842j:plain
沢山のノベルティグッズも頂きました!

以下、ハッカソンを通じて学んだことのメモみたいなものφ(`д´)メモメモ...

Finagle(ふぃねーぐる)とは、Twitter製の非同期RPCフレームワークで、RPCのシステムを作るためのフレームワーク

Apache Thriftのように、それ自体がRPCを提供するわけではない

  • 様々なプロトコルのServerとClientを簡単に作れる。
  • JSONのメッセージングとか簡単に作れちゃう。
  • FinagleはだいたいScalaで書かれている。
  • JVM上で動作する言語からも利用できるが基本的にScalaがオススメ


Twitter社が出しているEffective Scalaでは以下のように書かれている

Twitterにおいて、最も重要な標準ライブラリはUtilとFinagleだ。Utilは、ScalaJavaの標準ライブラリの拡張という位置付けで、それらに欠けている機能やより適切な実装を提供する。Finagleは、TwitterのRPCシステムで、分散システムの構成要素の中核だ。


FinagleはTwitter外でも使われている

TumblrPHPからScala(Finagle)に移行
  • FinagleがあるからScalaにした
  • Node.jsも検討したが、大規模で運用できるか不安があった
  • FinagleはTwitterでの実績がある
  • JVMだから安心

High Scalability - High Scalability - Tumblr Architecture - 15 Billion Page Views a Month and Harder to Scale than Twitter

Heroku:サンプルがもろにFinagle!!

Heroku | Scala on Heroku

Finagleのアーキテクチャ

f:id:takaya1219:20120616053230p:plain

  • 中ではNettyが動いている
    • NettyはJava NIOをラップしている
    • ノンブロッキングなI/O操作ができる
  • FinagleはJBoss Nettyをラップして使いやすくしたもの
  • Filter, Codec, Serviceという概念がある

Twitter Finagle server as an alternate HTTP ser... - Scala Resources - Quora

Finagleの要素

重要な要素はFuture, Service, Filter, Codecの4つ!

Futureクラス
class Future[+A]{
    def apply():A
}
  • 非同期計算の結果を表すクラス
  • 計算中、失敗、完了の3状態をとる
  • JavaのFutureとの違いとして写像(map)や合成(flatMap)がある
Service

Finagleにおけるロジックを実装する部分

class Service[-Req,+Rep] extends (Req) => Future[Rep]{
  def apply(request:Req):Future[Rep]
}
  • Req型を受け取ってFuture[Rep]型を非同期に返す関数
  • Server
    • Serverは任意のプロトコルに任意のServiceを結びつける
//EchoServerの例
val server:Server = ServerBuilder()
  .codec(Http())
  .bindTo(new InetSocketAddress(8000))
  .name("ServerName")
  .build(service)
  • Client
    • Clientは任意のプロトコルのServiceそのもの
//EchoClientの例
val client: Service[HttpRequest, HttpResponse] = ClientBuilder()
  .codec(Http())
  .hosts(new InetSocketAddress("localhost",8000))
  .build()
Filter

FilterはServiceに対して何か変換を行ったりする

class Filter[-ReqI, +RepO, +ReqO, -RepI] extends(ReqI, Service[ReqO,  RepI])=>Future[RepO] {
  def apply (request: ReqI, service: Service[ReqO, RepI]): Future[RepO]
}
Codec
  • Codecは、NettyにPipelineと密接な関係がある
  • Codecは、各プロトコルのencodeとdecodeを司るNettyとのつなぎ役
  • Finagleに標準でサポートされているCodec
    • HTTP
    • Stream(Http chunked transfer encoding)
    • Memcached
    • protocol buffer
    • Redis
    • Thrift
    • Kestrel
trait Codec[Req,Rep]

//Httpの例
val client: Service[HttpRequest,HttpResponse] = ClientBuilder()
  .codec(Http())
  .hosts(address)
  .build()

//Memcachedの例
val client: Service[Command, Response] = ClientBuilder()
  .codec(Memcached())
  .hosts(address)
  .build()

その他の機能

  • Server Support
    • Backpressure
    • Service Registration
    • Native OpenSSL bindings
  • Client Support
    • Connection Pooling
    • Load Balancing
    • Failure Detection
    • Failover/Retry
    • Distributed Tracing(a la Dapper)
    • Service Discovery(e.g., via Zookeeper)
    • Rich Statistics
    • Native OpenSSL bindings
    • Sharding

Hello World

  • Echoサーバ/クライアントでHello Worldを出力

Server側:HelloServer.scala

import com.twitter.util.Future
import com.twitter.finagle.Service
import com.twitter.finagle.builder.Server
import com.twitter.finagle.builder.ServerBuilder
import java.net.InetSocketAddress

object HelloServer {
  def main(atgs:Array[String]){
    val service = new Service[String,String]{
      def apply(request: String) = Future.value(request)
    }
    val server:Server = ServerBuilder()
            .codec(StringCodec)
            .bindTo(new InetSocketAddress(8080))
            .name("TestServer")
            .build(service)
  }
}


Client側:HelloClient.scala

import com.twitter.finagle.Service
import com.twitter.finagle.builder.ClientBuilder
import java.net.InetSocketAddress

object HelloClient {
  def main(args:Array[String]){
    val client:Service[String,String] = ClientBuilder()
        .codec(StringCodec)
        .hosts(new InetSocketAddress("localhost",8080))
        .hostConnectionLimit(1)
        .build()
            
    client("Hello, Finagle!!\n") onSuccess{ result =>
      println(result)
    }onFailure { error => 
      error.printStackTrace()
    }ensure{
      println("end")
      client.release()
    }
  }
}

実行結果

Hello, Finagle!!