JavaScriptでK-means法してみた

集合知プログラミング勉強会でK-means法を勉強したので

復習とJavaScriptの練習を兼ねて、クラスタリングの定番アルゴリズム「K-means法」をビジュアライズしてみた - てっく煮ブログJavaScript版を作ってみました。

K-Means clustering Visualiser - jsdo.it

PointsとKの値を適当に変えて[Initialize]ボタンを押した後、[Step]ボタンを押すと各クラスタが更新されていきます。 Firefox 16とChrome 22あたりなら動くはず。

ソースコードはGitHubに置いてあります。 ser1zw/k-means-visualiser-js

PythonでOpenCVを使おうとして ImportError: No module named cv って言われたら

環境

なにごと?

Pythonを覚えたら、やっぱりOpenCVやりたくなるじゃないですか。 で、おもむろにOpenCVを BUILD_PYTHON_SUPPORT=ON にしてインストールし、意気揚々とPythonを起動して

import cv

ってやるじゃないですか。

>>> import cv
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named cv

エラーになるじゃないですか。

なんでかなーと思ってPythonのモジュールのパスを調べてみると

>>> import sys
>>> print sys.path
['', '/usr/local/lib/python2.7/dist-packages/ipython-0.13.1-py2.7.egg', (以下略)]

OpenCVのPythonモジュールのパスが含まれてなさそうです。

OpenCVのPythonモジュールは、OpenCVをインストールしたディレクトリ配下の lib/python2.7/dist-packages にあるので、 このディレクトリを sys.path に追加してみます。

>>> import sys
>>> sys.path.append("/path/to/opencv/lib/python2.7/dist-packages")
>>> import cv
>>> cv.LoadImage("lenna.png")
<iplimage(nChannels=3 width=512 height=480 widthStep=1536 )>
>>>

どうやらできたっぽいですね。

OpenCVのモジュールを使うたびに毎回これをやるのは面倒なので、$PYTHONPATH にパスを追加しておきましょう。 .zshrcとかに

export PYTHONPATH=/path/to/opencv/lib/python2.7/dist-packages:$PYTHONPATH

って書いておけばよいです。

参考

InstallGuide : Debian - OpenCV Wiki

tmuxinatorのzsh用補完関数

tmuxinatorというのは

tmuxinator とは

tmuxinatorとは、tmuxで起動するセッションを予め定義しておき、コマンド一発でそのセッションを起動できるようにしたものです。ちなみに、screenで同じことをするscreeninatorというツールもあります。こちらが先に開発されたようです。

tmuxinatorで一瞬で開発環境を起動する #Ruby #開発環境 #AdventCalendar #tmux - Qiita

コマンド1発で、tmuxでいつも使っているセッションが開けるようになる便利ツールです。

このコマンドのzsh用補完関数をだいぶ前に作ってあったので、貼っておきます*1。FIXMEとか書いてあるけど気にしない。
zsh completion for tmuxinator — Gist

インストール

まず補完関数用のディレクトリを作って

$ mkdir -p ~/.tmuxinator/completion

gistからファイルを取ってきて入れておきます。

$ wget https://raw.github.com/gist/2242920/c8cd399ec3ae2579cd103206e89d495a27862a05/_tmuxinator
$ mv _tmuxinator ~/.tmuxinator/completion

最後に、.zshrcに以下のように追記すれば完了です。

fpath=($HOME/.tmuxinator/completion ${fpath})
autoload -U compinit
compinit

使い方

$ mux [TAB] とやれば、コマンドの候補が出てくるようになります。

f:id:ser1zw:20121008194441p:plain

$ mux start [TAB] とかやれば、候補のプロジェクトがずらっと出てきます。

f:id:ser1zw:20121008194517p:plain

tmuxinator、結構便利なので、みんな使うとよいですよ。

OracleでTwitterのタイムラインをSELECTする

  1. FDWってなによ?
  2. FDW(Foreign Data Wrappe),外部データラッパっていうやつで、SQL/MED(Management of External Data)の規格の一つで簡単にいうと、PostgreSQLにQUERYを発行したら、あら不思議、外部の(たとえばMySQLとかCSV)データが取得できるという変態機能。 twitterAPIに変更あるらしいから今後はわからにけど、twitterのデータを取ってくるとかもできる。というかラッパーが用意されてる。(ちなみに使ってみたら楽しかったw)

PostgreSQLに興味がある人向けにまとめてみた。|PostgreSQL|お仕事メモ|Pictnotes

それはワクテカ過ぎる... だがしかし SQLite3 でも出来る!きっと出来る!

Big Sky :: SQLite で twitter のタイムラインを select する。

Oracleでもきっとできる!というかできた!
ser1zw/twitter-public-timeline-for-oracle

f:id:ser1zw:20121005015127p:plain

ご家庭のOracleで、いつでも新鮮なPublic timelineがお楽しみいただけます!

環境

ソースコード

GitHubに置いてあります。 ser1zw/twitter-public-timeline-for-oracle

インストールには、後述の

を行ったあと、SQL*Plusで同梱のinstall.sqlを実行してください。

$ sqlplus YOUR-USER-NAME/YOUR-PASSWORD@localhost:1521/XE @install.sql

インストールすると、TWITTER_PUBLIC_TIMELINEというビューが作成されます。これをSELECTすれば、Public timelineが取得できます。

SELECT created_at, screen_name, text FROM TWITTER_PUBLIC_TIMELINE WHERE LOWER(text) LIKE '%http%';

アンインストールには、同梱のuninstall.sqlを実行してください。

仕組み

という感じで処理をしています。
以下、それぞれどんな感じなのかざっくり解説!

PL/SQLのHTTP機能

OraclePL/SQLでは、UTL_HTTPパッケージの機能を使うことで、HTTPアクセスができます。

TwitterのPublic timelineからGETするのはこんな感じです。

DECLARE
  url VARCHAR2(100) := 'http://api.twitter.com/1/statuses/public_timeline.xml';
  request UTL_HTTP.REQ;
  response UTL_HTTP.RESP;
  buff VARCHAR2(4000);
BEGIN
  UTL_HTTP.SET_RESPONSE_ERROR_CHECK(FALSE);
  request := UTL_HTTP.BEGIN_REQUEST(url, 'GET');
  UTL_HTTP.SET_HEADER(request, 'User-Agent', 'Mozilla/4.0');
  response := UTL_HTTP.GET_RESPONSE(request);

  IF response.status_code = 200 THEN
    BEGIN
      LOOP
        UTL_HTTP.READ_TEXT(response, buff, LENGTH(buff));
        DBMS_OUTPUT.PUT_LINE(buff);
      END LOOP;
      UTL_HTTP.END_RESPONSE(response);
    EXCEPTION
      WHEN UTL_HTTP.END_OF_BODY THEN
        UTL_HTTP.END_RESPONSE(response);
    END;
  ELSE
    UTL_HTTP.END_RESPONSE(response);
    DBMS_OUTPUT.PUT_LINE('Fail: STATUS CODE: ' || response.status_code);
  END IF;
END;

ただし、使用するにはちょっとだけ準備が必要です。

utlhttp.sql を実行してUTL_HTTPパッケージをセットアップ

スクリプトを実行するだけです。 $ORACLE_HOME/rdbms/admin に utlhttp.sql というスクリプトがあるので、SQL*Plusなどで実行します。 Oracleが動いているサーバでこんな感じのコマンドをたたけばOKです(パスワードやSIDは必要に応じて変更してください)。

$ cd $ORACLE_HOME/rdbms/admin
$ sqlplus SYS/YOUR-PASSWORD@localhost:1521/XE AS SYSDBA @utlhttp.sql

ネットワークのアクセス制御リスト(ACL)の設定

11gから外部ネットワークへのアクセスの際にアクセス制御が行われるようになり、アクセスするユーザやホストを設定しなければならなくなりました。 ユーザ SCOTT が ホスト api.twitter.com にアクセスできるようにするには、こんな感じで設定すればOKです。

DECLARE
  user VARCHAR2(30) := 'SCOTT';
BEGIN
  DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('www.xml', 'WWW ACL', user, TRUE, 'connect');
  DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE('www.xml', user, TRUE, 'resolve');
  DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('www.xml', 'api.twitter.com');
END;

ちなみに、最後のアクセス制御リストへの追加を

  DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('www.xml', '*');

にすれば、どこでもアクセスできるようになります。

参考:DBMS_NETWORK_ACL_ADMIN

XML処理機能

Oracle XML DBの機能を使うと、XMLデータをリレーショナルデータとして(テーブルに入ったデータと同じような感じで)扱えます。 今回はPublic timelineのXMLデータから各ツイートをとり出すために、XMLTableを使っています。 これがなかなか便利な機能でして、例えばこんな感じのHOGE_XMLテーブルがあったとして

-- HOGE_XMLテーブル
CREATE TABLE HOGE_XML (
  HOGE_ID INTEGER PRIMARY KEY,
  XML_DATA CLOB
)

こんなXMLデータがHOGE_XMLテーブルのXML_DATA列に入っている場合

<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
  <id>123456789</id>
  <text>ほげほげ</text>
  <user>
    <id>12345</id>
    <name>hoge</name>
  </user>
</status>
<status>
  <id>234567890</id>
  <text>ふがふが</text>
  <user>
    <id>23456</id>
    <name>fuga</name>
  </user>
</status>
<status>
  <id>345678901</id>
  <text>ふーばー</text>
  <user>
    <id>34567</id>
    <name>foo</name>
  </user>
</status>
</statuses>

こんな感じのSQLを実行すれば、1つの<status>の要素が1つのレコードとして返ってきます。 もちろんWHERE句も使えます。超素敵です。

SELECT
  X.*
FROM
  HOGE_XML H,
  XMLTABLE('/statuses/status'
    PASSING XMLTYPE(H.XML_DATA)
    COLUMNS
      ID VARCHAR2(10) PATH 'id',
      TEXT VARCHAR2(1000) PATH 'text',
      USER_ID VARCHAR2(10) PATH 'user/id',
      USER_NAME VARCHAR2(100) PATH 'user/name'
  ) X
WHERE
  X.USER_NAME IN ('hoge', 'fuga')

f:id:ser1zw:20121005015402p:plain

テーブル・ファンクション(表関数)

テーブル・ファンクションというのは、

テーブル・ファンクションは、行のコレクション(ネストした表またはVARRAY)を戻すユーザー定義のPL/SQLファンクションです。SELECT文のTABLE句の内部でテーブル・ファンクションを起動することで、データベース表のようにこのコレクションから要素を選択できます。

http://docs.oracle.com/cd/E16338_01/appdev.112/b56260/tuning.htm#i52954

です。 要は、

SELECT * FROM TABLE(hoge_func(123));

みたいな感じで戻り値をそのままSELECTできるストアドファンクションです。処理のパイプライン化もできます。

ただしSELECTするときにTABLE句が必要になるので、今回は、

CRATE VIEW TWITTER_PUBLIC_TIMELINE
AS
SELECT
  *
FROM
  TABLE(GET_TWITTER_PUBLIC_TIMELINE);

のようなビューを作成し、毎回TABLE句をつけないで済むようにしてみました。

まとめ

そんなわけでOracleでもTwitterのタイムラインを取ってくることができたわけですが、2013年3月5日でXMLのサポートが打ち切られちゃうので、今回のやつは使えなくなります。認証もしてないし。

元ネタであるPostgreSQLtwiter_fdwでは、WHERE句に q = 'hoge' で指定した条件がSearch APIにパラメータとして渡されるようになってるみたいですね。Oracleだとこういう仕組みは作れるのかな…?

YARDで拡張ライブラリのドキュメントを書くときはメソッドの定義のところで@overloadタグを書かなきゃダメという話

はじめに

まぁ表題のとおりなんですが、要は
「YARDで拡張ライブラリのドキュメントを書くときは、@overloadタグでメソッドシグニチャを書かないと正しくドキュメントが生成されないので注意しましょう」
という話です。

環境

何が起こったかというと

拡張ライブラリで、Hashを渡すメソッドのドキュメントをYARDでこんな感じで書いてたんですよ。

/*
 * @param [Hash] opts parameters
 * @option opts [Number] :arg1 argument 1
 * @option opts [Number] :arg2 argument 2
 */
VALUE rb_foo(VALUE self, VALUE opts) {
  return Qnil;
}

で、

$ yardoc foo.c

とかやって作成したドキュメントを意気揚々と開いたわけですよ。

そしたらなんと、@optionで指定した :arg1 と :arg2 のドキュメントが出てこないじゃないですか。

f:id:ser1zw:20120430181745p:image

で、どうしたかというと

YARDのリポジトリにIssue登録を投げてみたら、
「CのコードでYARDを使うときは@overloadタグでメソッドシグニチャとかパラメータの記述をしないとちゃんと認識できねーよ」
との回答を頂いたので、こんな感じに書きなおしてみました。

/*
 * @overload foo(opts)
 *   @param [Hash] opts parameters
 *   @option opts [Number] :arg1 argument 1
 *   @option opts [Number] :arg2 argument 2
 */
VALUE rb_foo(VALUE self, VALUE opts) {
  return Qnil;
}

そしたらちゃんと@optionタグで指定した :arg1 と :arg2 の内容が表示されてました。

f:id:ser1zw:20120430181912p:image

まとめ

というわけで、YARDを拡張ライブラリで使う場合は@overloadタグをつけましょうね!というお話でした。

HWエンキューでロックされているセグメントを特定する

はじめに

Oracleまわりのトラブルの調査のため、HWエンキューでロックされたセグメントを特定する方法を調べてみました。

環境

HWエンキューってなんぞ?

Oracleのエンキューとは

エンキューは、データベース・リソースへのアクセスをシリアライズする共有メモリーの構造(ロック)です。
(Oracleエンキュー名)

です。
HWエンキューは、セグメントのHWM(High Water Mark; 最高水位標)を動かすときに行われるロックです。保持されているロック情報を示すV$LOCKビュー上では、TYPE='HW'のレコードとして表されます。

HWエンキューでロックしているセグメントを特定する

1. ロックされたHWエンキューが待っているデータのファイルとブロックを特定

まず、V$LOCKからTYPEが'HW'の行を探し、そのデータブロックアドレスのファイル番号とブロック番号を取得します。

HWエンキューの場合、V$LOCKのID1, ID2は下記のようになります。

  • ID1: HWMが変更されるセグメントが格納されている表領域の番号
  • ID2: セグメントヘッダの相対データブロックアドレス

(パフォーマンス・ビューを使用したインスタンスのチューニング - HWエンキュー)


また、ストアドファンクションDBMS_UTILITY.DATA_BLOCK_ADDRESS_FILEとDBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCKにデータブロックアドレスを渡して実行すると、そのデータブロックアドレスのファイル番号とブロック番号がわかります。

DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE
引数 dba にデータ・ブロック・アドレスを渡して実行すると、データ・ブロック・アドレスのファイル番号部分を返す
(DATA_BLOCK_ADDRESS_FILEファンクション - DBMS_UTILITY)

DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE (
   dba NUMBER)
  RETURN NUMBER;

DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK
引数 dba にデータ・ブロック・アドレスを渡して実行すると、データ・ブロック・アドレスのブロック番号部分を返す
(DATA_BLOCK_ADDRESS_BLOCKファンクション - DBMS_UTILITY)

DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK (
   dba NUMBER)
  RETURN NUMBER;


そこで、V$LOCKのID2をDATA_BLOCK_ADDRESS_FILEとDATA_BLOCK_ADDRESS_BLOCKに渡せばよさそうです。
SQLはこんな感じになります。

SELECT
     DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(ID2) "FILE_ID",
     DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(ID2) "BLOCK_ID"
FROM
     V$LOCK
WHERE
     TYPE = 'HW'

結果はこんな感じ。ファイル番号とブロック番号がわかりました。

FILE_ID BLOCK_ID
20 29


2. ロックしているセグメントを特定
1.でわかったファイル番号とブロック番号から、HWエンキューでロックしているセグメントを特定します。
こんな感じのSQLを実行します。

SELECT
     OWNER,
     SEGMENT_NAME,
     SEGMENT_TYPE
FROM
     DBA_EXTENTS
WHERE
     FILE_ID = 20
AND 29 BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS - 1

WHEREの条件の値(上記の20と29)には、1.で調べたものを入れてください。
結果はこんな感じ。

OWNER SEGMENT_NAME SEGMENT_TYPE
ORACLE SYS_LOB000001234C01234$$ LOBSEGMENT

どうやら SYS_LOB000001234C01234$$ というセグメントがロックされているらしい、ということがわかりました。
この情報をもとに原因を特定して、対策を行いましょう。

まとめ

HWエンキューでロックされているセグメントを特定する方法を調べてみました。
これでHWエンキューでずーっとロックされてエラいことになっても大丈夫ですね!

Scientific Linux 6.2にOracle XE 11g R2をインストールする

はじめに

Scientific LinuxOracleのデータベースをインストールしたので、手順を書いておきます。

環境

  • Scientific Linux 6.2 x86_64
    • インストール時のパッケージ選択では Basic Server を選択
  • Oracle Database Express Edition 11g Release 2

手順

1. まずはダウンロード
下記からパッケージをダウンロードします。
Oracle Database Express Edition 11g Release 2のダウンロード
Windows用(32bit版)とLinux用(64bit版)がありますが、今回はLinuxに入れるので
Oracle Database Express Edition 11g Release 2 for Linux x64
のほうをダウンロードしてきます。
f:id:ser1zw:20120319004941p:image
ダウンロードにはOracleのユーザ登録が必要です。事前にこのあたりから登録してください。


2. 必要なパッケージをインストール
と言ってもScientific LinuxをBasic Serverとしてインストールしたら、特に何もしないで大丈夫でした。
公式のドキュメントによると、

  • glibc should be greater than or equal to 2.3.4-2.41
  • make should be greater than or equal to 3.80
  • binutils should be greater than or equal to 2.16.91.0.5
  • gcc should be greater than or equal to 4.1.2
  • libaio should be greater than or equal to 0.3.104

http://docs.oracle.com/cd/E17781_01/install.112/e18802/toc.htm#BABHICJH

が必要らしいので、無い場合はyumなどでインストールしてください。


3. Oracleをインストールする
まずはダウンロードしたファイル(oracle-xe-11.2.0-1.0.x86_64.rpm.zip)を展開して、中身を確認します。

$ unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip
$ ls
Disk1  oracle-xe-11.2.0-1.0.x86_64.rpm.zip
$ cd Disk1/
$ ls
oracle-xe-11.2.0-1.0.x86_64.rpm  response  upgrade

中にrpmパッケージが入っているので、rootでインストールします。

$ su
パスワード:
# rpm -ivh oracle-xe-11.2.0-1.0.x86_64.rpm 
準備中...                ########################################### [100%]
   1:oracle-xe              ########################################### [100%]
Executing post-install steps...
You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.

次に、 /etc/init.d/oracle-xe configure を実行しろとのことなので、実行しましょう。
途中、

  • Application Expressのポート番号(デフォルトは8080)
  • データベースリスナーのポート番号(デフォルトは1521)
  • DBのアカウントのパスワード(SYSとSYSEMもこのパスワードになる)
  • OS起動時にOracleを起動するかどうか(デフォルトはyes)

について聞かれるので、適宜設定します。

# /etc/init.d/oracle-xe configure

Oracle Database 11g Express Edition Configuration
-------------------------------------------------
This will configure on-boot properties of Oracle Database 11g Express 
Edition.  The following questions will determine whether the database should 
be starting upon system boot, the ports it will use, and the passwords that 
will be used for database accounts.  Press <Enter> to accept the defaults. 
Ctrl-C will abort.

Specify the HTTP port that will be used for Oracle Application Express [8080]:

Specify a port that will be used for the database listener [1521]:

Specify a password to be used for database accounts.  Note that the same
password will be used for SYS and SYSTEM.  Oracle recommends the use of 
different passwords for each database account.  This can be done after 
initial configuration:
Confirm the password:

Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]: 

Starting Oracle Net Listener...Done
Configuring database...Done
Starting Oracle Database 11g Express Edition instance...Done
Installation completed successfully.

成功したようです。rootでの作業はここまで。


4. 環境変数を設定する
ORACLE_HOMEなどの環境変数の設定です。下記のシェルスクリプトで必要なものを設定してくれるようになっています*1

/u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

というわけで、Oracleを使うユーザの.bashrcに以下の1行を追加するだけで完了です。

. /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

念のため、.bashrcを読みなおしておきましょう。

$ source ~/.bashrc

これでパスの設定などが行われ、sqlplusが使える状態になります。


5. 動作確認する
sqlplusを起動し、systemでログインしてOracleのバージョンを表示してみます。
パスワードは手順3.の途中で入力したものを入れればOKです。

$ sqlplus system

SQL*Plus: Release 11.2.0.2.0 Production on 日 3月 18 01:24:57 2012

Copyright (c) 1982, 2011, Oracle.  All rights reserved.

パスワードを入力してください: 


Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
に接続されました。
SQL> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
CORE    11.2.0.2.0      Production
TNS for Linux: Version 11.2.0.2.0 - Production
NLSRTL Version 11.2.0.2.0 - Production

うまくいったっぽいですね。

まとめ

そんなわけで、Scientific LinuxにOracle XE 11g R2をインストールしてみました。
特にハマることもなく、すんなりインストールできるもんですね。

*1:これはbash用のものですが、同じディレクトリにcsh用の oracle_env.csh も用意されています