Oracleは大好きです。ウソです。でもOracle 11g XEをubuntuにインストールしたいです。ここには、くどくどと説明があります。カーネルのパラメータとかを調整したりしています。そんなにがんばらなくてもいいので、とりあえず動くようにします。
[続きを読む…]
Oracleは大好きです。ウソです。でもOracle 11g XEをubuntuにインストールしたいです。ここには、くどくどと説明があります。カーネルのパラメータとかを調整したりしています。そんなにがんばらなくてもいいので、とりあえず動くようにします。
[続きを読む…]
http://blog.liris.org/2011/09/javascript.html
Google Closure?これは、Googleの製品に使われているだけあって、安心感があります。ウィジェットも安定・充実しています。コードもおいやすくとてもいいライブラリです。ただ、使い続けていると、世の中の流れはhtml5ですがClosureはその流れに取り残されている感があります。NotificationのAPIやファイルのドラッグ&ドロップ、ローカルストレージなどの機能がないだけじゃなく、今後の方向性がよく分かりません。分かっていないのは僕だけかもしれませんが。ただ、このあたりは我慢できます。
ちょっと聞き捨てならないことが書いてあったので、身内から突っ込んでおきます。
あります。
Closure Libraryでわからないことがあったら伊藤千光さんのブログを読んでください。
ちなみにこのgoog.events.FileDropHandlerは名前のとおりファイルのドロップを検出するだけなので、ドロップしたファイルを表示したりサーバーにアップロードしたりは他のコンポーネントを組み合わせるなりして自分で実装する必要があります。
1つのクラスが1つのことしかしないというのはJavaのイディオムなんですかね。
あります。
Closure Libraryでわからないことがあったら伊藤千光さんのスライドを読んでください。
userData behaviorを使っているのでIE6でも動作するそうです。
確かにありません。
そもそもNotification APIのどの辺がHTML5なんですか?ここにはdroppedって書いてあります。
というのもFirefoxはモバイルだけ対応してデスクトップは放置中だしIEはピン留め+通知機能があるので、標準化までまだ時間がかかりそうな機能に見えます。
それに対応してないから時代遅れってのはちょっと可哀想です。
HTML5の定義についてteramakoさんがわかりやすく解説しているので読んでください。
前回は Python で文書の類似度判定を行うプログラムのアルゴリズムについて紹介しました。
今回の話は、前回の類似度判定を行うプログラムの使い方と、前回の記事のアルゴリズムを用いた文書の類似度検索を行うプログラムの設計と類似度判定プログラムの実装について紹介します。
また、作成したプログラムのコードは github [1] に上げました。
まずは使い方。github からコードをダウンロードして、以下のコマンドを叩きます (argparse を使っているので python2.7 以降じゃないと動かないです、あと形態素解析に “MeCab” [2] を使っているので、そっちもインストールしてください) 。
1 |
ohyama@ariel:~/Suneo$ python search_with_vsm.py -f SENTENCE_PATH |
コマンドライン引数の SENTENCE_PATH は、既知の文書のデータファイルのパスになります。ここで言っている “既知の文書” とは、プログラム起動後に受け付ける入力文書との比較対象になる文書群になります。このプログラムは、これら事前に用意した文書と、入力文書がどれだけ似通っているかを判定するプログラムです。
ファイルのフォーマットは、各行が比較対象となる一文書に対応します。なので、以下の要領で作成してください
[既知の文書のデータファイルの記述例]
1 2 3 |
本日は晴天なり明日はわからん 今日も窓から眺める富士山の景色がうつくしー ... |
まずは、アウトラインの構造とデータ構造について見て行きます。
このプログラムは以下のファイル構造になってます。
1 2 3 4 5 |
/Suneo |-- search_with_vsm.py |-- Sentence/ |-- sentence.py |-- word.py |
これを見てわかるように、クラス構造はとても単純です。Sentence ディレクトリ以下の 2 つのファイル (sentence.py, word.py) がクラス定義と実装で、search_with_vsm.py がその他の所々の処理を行う Suneo 本体のスクリプトファイルです。
次に Suneo のスクリプトファイルの処理について簡単に見てみます。
ますは初期化処理として、コマンドライン引数で指定したファイルの各行を読み込み、Sentence オブジェクトを作り、更に単語に分解して Validword オブジェクトを作り、それぞれに関連を持たせます。
そして、標準入力から受け取った文書を単語に分割し、各単語に対応する Validword オブジェクト群を取得し、分割した単語を含む Sentence オブジェクトの文書に対して、入力文書との比較処理を行います。
比較処理は、前回紹介したベクトル空間モデルにおける内積によって、類似度を算出する手法を使います。有効語は、面倒くさいので既存文書が含む全単語要素に設定しています。
これにより有効語数が N の時、有効語の出現頻度を特徴ベクトルとした N 次元ベクトルで各文書を表現できます。
あとは、既存の各文書と入力文書のベクトルの内積を取って、それぞれのベクトルの大きさの積で正規化してやれば、類似度を 0 から 1 までの実数で表現できます。
ただこれだけだと、一見して単なる単語一致検索と同じように見えてしまいます。有効語と既知の単語群の集合が同じなのは明らかに多すぎなので、有効語を何らかの基準で絞って次元削減するとそれっぽい結果になると思います。
更なる発展形としては、有効語の類義語も有効語にするとかすると、更にオモロい結果になると思いますが。気が向いたらやります。
[1] https://github.com/userlocalhost2000/Suneo
[2] http://mecab.sourceforge.net/
以前、どこかで書いたかもしれませんが、会社の製品では、WebアプリケーションのJavaScriptのライブラリはGoogle Closureを使っています。もっと前はprototypes.js + なんかというとても素敵な感じでした。それが、一年ほど前にGoogle Closureを使うように変更されました。会社のもう一つのものは、Extを使っています。これは豆知識です。Google Closureを選択するときに検討したモノがjQueryです。ExtはIE6とかあり得ないブラウザでのパフォーマンスなどの問題で選考から落ちました。
[続きを読む…]
今後のアリエルのために、新卒の育成カリキュラムを考えています。基本的にはWebプログラマとして一人前になることを目指すカリキュラムです。
教科書に自分の書いた本を指定しているのは買わせて儲けようというせこい発想ではなく(直近でアリエルが大量の新卒を採るわけではないので本音です)、単に教えやすいからです。誤読の可能性はゼロですし、本に何が書かれていないかを完全に分かっています。
色々切り捨てて、Webでプログラミングするならこれぐらいは最低限必要、と思える分野に絞ったつもりですが…それなりに分量があります。今時のWebプログラマは大変です。教える期間は3ヶ月ぐらいと思っていましたが、全部書き出してみると無理な気がしてきました。
各論のコメントは後日、別記事で書きます。
プログラミング基礎
– Java
– 教科書「パーフェクトJava (PERFECT SERIES) (PERFECT SERIES 2)」
システム
– OS
– Unix哲学
– スクリプティング言語(触りだけ)
– 正規表現
– インターネット
– TCP/IP、DNS
– メールのプロトコル
– サーバ管理ツール
– ソケットプログラミング(触りだけ)
– クラウド
– 業界動向
Webプログラミング
– Webのプロトコル
– HTTP
– データフォーマット
– Web API
– Webアプリの構造
– 基本構造
– アーキテクチャの変遷と業界動向
– Javaで作るWebアプリ
– サーブレットAPI
– MVCフレームワーク
– クライアントプログラミング
– 教科書「パーフェクトJavaScript」
– データベース
– RDB
– ORM
– 業界動向
– コードリーディング
– 静的解析(どこから読むか、どう読むか)
– デバッグ(動的解析の技法)
– Webセキュリティ
– 脆弱性
– 業界動向
– WebのUX
ソフトウェア開発
– 開発プロジェクト
– 開発ツール
– UML
– 業界動向
– テスト
– ソフトウェアライセンス
– エディタや各種ツールの使い方
– 計算機理論
– アルゴリズムとデータ構造
– 低レイヤ言語(C言語)
– Androidアプリ開発
– 闘うプログラマー[新装版] ビル・ゲイツの野望を担った男達
気合をいれたくなった時に読んでください。読んで熱い気持ちになれなかったらプログラマをやめたほうがいいです。
– 達人プログラマー―システム開発の職人から名匠への道
現場経験を経てから読むことを勧めます。腑に落ちなかったらまだ読むのが早いので、しばらく積んでおいてください。
ゲーデル、エッシャー、バッハ―あるいは不思議の環 20周年記念版
まとまった休みに読んでください。読んで興奮しなかったらプログラマをやめたほうがいいです。
MINIXオペレーティング・システム (アスキーブックス)
代わりにLinuxカーネル本やBSD本でもいいですが、最低一冊はOSの本を読むべきです。何について書かれているのかすら理解できない場合、OS入門書的な本を先に読んでください。
– ネットワークの良い本
– RDBの良い本
個人的に Python が熱いです。以前にも同じような事を言った気がしますが。多分デジャブです。
Python といえば、アリエルには言わずと知れた Python 界隈の大物が御座しますが。そんな大物の縄張りで、僕のようなチンピラがこれまた安っちい記事を書くのはかなり恐縮ですが。その辺りは気にせず、図太い精神で書いてこうと思います。
Python は、再帰の途中で内部状態を維持しつつ途中結果を返すジェネレータだったり、(mutable ながら)リストに対して map とか filter とか出来ちゃうところで Lisp を感じられる辺り、かなりオモロい言語です。
せっかくだし何か書きたいなという事で、ベクトル空間モデル [1] を使った類似文書検索プログラムを作ってみました。
出来たものだけ見せると、以下のように動作します。
入力文書は標準入力から受け取ってます。4 行目の「国会図書館は…」が入力になります。結果に、入力文書が既知の文書に対してどれだけ似通ってるかの度合い (類似度) を 0 から 1 の範囲で示してくれます。
どうやって類似度を判定しているのかと言いうと。
その文書を特徴づける「何か」を何個か見つけて、そいつらを単位ベクトルに突っ込む処理を各文書に対して行います。
そして、それら個々のベクトルと入力文書を当該ベクトル空間にマッピングしたベクトルとの内積を取れば、既存の文書と入力文書がどれだけ似通ってるのかを数値化できます。
ご存知のとおり、内積はベクトル空間で直交した場合には 0 になりますし、各ベクトルの大きさの積で正規化してやれば、値を 0 から 1 の範囲にできるので、類似度を測るにはとっても便利な演算です。
この手法はかなり古典的ですが、特徴ベクトルさえ定義してやれば、文書の類似度判定だけでなく、顔認証や指紋認証といったあらゆる物理事象に対して応用できる、とってもオモロい手法です。
今回は Python の練習みたいなものなので、結果の正確性の検証や類似研究とかの比較は特にやってません。あしからず。
それでは早速やってみます。文書を特徴づける特徴ベクトルを「文書に含まれる単語」にします。一般に、機械学習の分野では「特徴ベクトルを定義しまくると結果の正確性が悪くなる」ということが知られています。
文書の類似度を算出する今回のプログラムにおいても、特徴ベクトルを規程する単語も、適当にいろんな単語を突っ込むよりも、その文書を特徴づけると思われる単語群 (類義語検索の分野では「有効語」とか言われているみたいです) を規程するのがベターです。
ここで問題が。文書の類似度を判定する為の特徴ベクトルを有効語とすると、文書から単語を取り出すプログラムが必要になってきます。
さすがにそこまで Python で自作する元気は無いので、既存の形態素解析ツール [3] を使わせてもらいました。
さて、材料は揃いました。以上をふまえて、文書の類似度を計測する Python プログラムを作ってみたの話。
[ (長くなったので) 次回に続く ]
[1] http://www.yc.tcu.ac.jp/~kiyou/no5/P099-109.pdf
[2] http://mecab.sourceforge.net/
デバッグ用として開発コードにconsole.logを埋め込み、消し忘れたままコミット、IEでスクリプトエラーが発生して動かなくなりました
なんて経験ありませんか?
例えばClosure Compilerでリリースビルドから自動的にconsole.logを消してくれればそんなことなくなります。
まず前提知識として、Closure Compilerはコンパイル時の流れはこんな感じです。
ASTに対する操作をpassと呼んでいて、自作のpassを追加できるオプションがあります。
こちらの本に詳細が載っています。
build.xmlとMyCommandLineRunner.javaは上記Closure本の丸パクリなので添付のソースを見てください。
まあこのConsoleRemoval.javaもClosureCodeRemoval.java(goog.asserts.assertとかを消すpass)のパクリなのですが。
http://dev.ariel-networks.com/wp/wp-content/uploads/2011/08/compiler.zip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
final class ConsoleRemoval implements CompilerPass { static final DiagnosticType MESSAGE_CONSOLE_REMOVAL_DESCRIPTION = DiagnosticType.warning("JSC_MSG_Forgets to erase console. ", "Forgets to erase {0}."); private final AbstractCompiler compiler; private final List<Node> consoleCalls = Lists.newArrayList(); private class FindConsoleCalls extends AbstractPostOrderCallback { Set<String> consoleNames = Sets.newHashSet(); FindConsoleCalls() { consoleNames.add("console.assert"); consoleNames.add("console.clear"); consoleNames.add("console.count"); consoleNames.add("console.debug"); consoleNames.add("console.dir"); consoleNames.add("console.dirxml"); consoleNames.add("console.error"); consoleNames.add("console.exception"); consoleNames.add("console.group"); consoleNames.add("console.groupCollapsed"); consoleNames.add("console.groupEnd"); consoleNames.add("console.info"); consoleNames.add("console.log"); consoleNames.add("console.memoryProfile"); consoleNames.add("console.memoryProfileEnd"); consoleNames.add("console.profile"); consoleNames.add("console.profileEnd"); consoleNames.add("console.table"); consoleNames.add("console.time"); consoleNames.add("console.timeEnd"); consoleNames.add("console.timeStamp"); consoleNames.add("console.trace"); consoleNames.add("console.warn"); } @Override public void visit(NodeTraversal t, Node n, Node parent) { if (n.getType() == Token.CALL) { String fnName = n.getFirstChild().getQualifiedName(); if (consoleNames.contains(fnName)) { t.report(n, MESSAGE_CONSOLE_REMOVAL_DESCRIPTION, fnName); consoleCalls.add(n); } } } } ConsoleRemoval(AbstractCompiler compiler) { this.compiler = compiler; } @Override public void process(Node externs, Node root) { NodeTraversal.traverse(compiler, root, new FindConsoleCalls()); for (Node call : consoleCalls) { Node parent = call.getParent(); if (parent.getType() == Token.EXPR_RESULT) { parent.getParent().removeChild(parent); } else { Node firstArg = call.getFirstChild().getNext(); if (firstArg == null) { Node undefNode = new Node(Token.VOID, Node.newNumber(0)); if (call != null) { undefNode.copyInformationFromForTree(call); } parent.replaceChild(call, undefNode); } else { parent.replaceChild(call, firstArg.detachFromParent()); } } compiler.reportCodeChange(); } } } |
test.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
console.log('hoge'); // (1) console.log([1,2,3].map(function(n) { // (2) return n * n; }.join(','))); var a = { console: { log: function(s) { alert(a); } } }; a.console.log('fuga'); // (3) (function(console) { console.log('piyo'); // (4) })(a.console); |
をコンパイルすると
1 |
$ java -jar compiler/build/mycompiler.jar --js test.js |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
test.js:1: WARNING - Forgets to erase console.log. console.log('hoge'); ^ test.js:3: WARNING - Forgets to erase console.log. console.log([1,2,3].map(function(n) { ^ test.js:18: WARNING - Forgets to erase console.log. console.log('piyo'); ^ 0 error(s), 3 warning(s) var a={console:{log:function(){alert(a)}}};a.console.log("fuga");(function(){})(a.console); |
(4)で誤作動していますが、まあ実用範囲内でしょう。
optimize後であれば引数名が短縮されているので誤作動しなくなるかもしれませんが、ADVANCEDモードのときにconsole.traceとかは短縮されてしまうので消せなくなるんじゃないかと思います。(gecko_dom.js,webkit_dom.js)
ここではCommandLineRunnerを拡張しましたが、ビルドにantを使っているのであればCompileTaskを拡張してもよいでしょう。
ただCompileTaskはfinal classなので継承できませんが。
本題とは関係ないのですが、先日ブラウザー勉強会に参加しました。
興味深いお話を聞けて刺激になりました。
関係者の方スピーカーの方たちへお礼申し上げます。
あっ、あとO’ReillyのTwisted本の表紙はクサリヘビっぽい気がします。
子供のころに読んだ本の中で、毒を飲んでも死なない怪盗ルパンが、日頃から薄めた毒を服用しているので毒が効かない身体になったのだ、とネタばらしをするシーンがありました。
毒はともかく、常日頃から病原体を接種すれば病気に負けない身体になります。
空前の予防接種ブームに乗って、予防接種の予約をすることにしました。
予約希望日に19時から予定があるので、少し余裕を見て、希望時間を11:00から18:00に指定しました。最悪でも18時前に終われば次の予定に間に合うからです。
そして予約が成立したメールが送られてきました。
時刻は18:00から…
11時から18時の間が空いているという意思表示のつもりで11時から18時を送ったのに、18時から診察…、時間指定は難しいです。
来月9月にパーフェクトJavaScriptが出ます。紛らわしいですが、パーフェクトJava (PERFECT SERIES) (PERFECT SERIES 2)ではなくパーフェクトJavaScriptです(「パーフェクトJava」のJava7対応はしたいとは思っていますが未定です)。
今年4月に実践JS サーバサイド JavaScript 入門を出したので、1年に2冊執筆とは凄いな(=暇だな)、と思うかもしれません。自分の中では「実践JS サーバサイド JavaScript 入門」は去年執筆した本で「パーフェクトJavaScript」は今年執筆した本なので、1年1冊ペースです。
「実践JS サーバサイド JavaScript 入門」はタイトルに反してNode.jsの話が少ないじゃないかと言われましたが、今回の「パーフェクトJavaScript」は2章分もNode.jsに割きました。前作で消化不良を感じた人にも納得してもらえると思います。
JavaScriptの言語仕様もきっちり書きました。井上のJavaScript師匠、内田さんのレビューも受けているのでばっちりでしょう。「JavaScriptにはwindowというグローバルオブジェクトがあります」のような、いい加減で微妙な説明はしていません。補足しておくと、言葉の使い方と概念を正しく合意できていれば、この説明自体あながち間違いとは言えません。しかし、JavaScript勉強中の人に、この説明でわかった気にさせるのは不誠実な態度だと思っています。
クライアントサイドJavaScriptはアリエルの新エース土江さんが、HTML5はYahoo! Japanの浜辺さんが執筆しました。
「実践JS サーバサイド JavaScript 入門」と5%ぐらい内容が被っているので両方買った人は少し金返せ、という気分になるかもしれませんがお布施と思って我慢してください。
アジャイル宣言の話の続きです。「アジャイル宣言の背後にある原則」の何が自分の心の中で消化できていない部分を書きます。
以下、ソフトウェア開発者を一般化したように書きますが、言うまでもなく世の中には多様な開発者がいます。簡単に一般化できるものではないことは理解しています。ただ、ある一定の傾向があると思っているだけです。いちいち例外もあります、とは断りませんが、例外があるのは当然です。
さて、ある種の人たちには、開発者は顧客視点が欠けている、という題目が信じられています。
これは必ずしも真実とは異なります。
ソフトウェア開発の過程で技術的好奇心が顧客視点を上回る場面があるのは否定しません。使う人の気持ちより作る楽しさに目を奪われることがあるのも否定しません。しかし純粋に技術的好奇心だけで開発が終始するプロジェクトは、ソフトウェア開発としては稀です。利用者がいる前提で作るソフトウェアで、使う人の満足度に対する意識が皆無なまま開発をする開発者がいれば奇跡的な存在です。
これを聞いて疑わしいと思う人もいるかもしれません。自分の知る開発者がそんな広い視野を持っている気はしないぞ、と思うかもしれません。
広い視野を持つ開発者ばかりだとは主張しません。あまり認めたくない事実ですが、どちらかと言えば開発者の視野は狭いんじゃないかな、とも思います。これは他の職種の人に比べて、という意味です。
ただ、開発者に欠けているのが顧客満足度の視点というのは誤解だと思っています。では何が欠けがちかと言うと、典型的な話が@ITのこの記事にある視点です。
端的に言うと金の話です。ソフトウェア開発で利益を出せるかの視点が、開発者の場合、相対的に低いんだと思います。
アジャイル宣言に話を戻します。
開発者にとって顧客満足を最優先するのは、これだけを取り出せば(一般に信じられているほど)難しい話ではないと思っています(目の前の問題に気をとられて部分最適になることはあるにせよ)。変更の要求を受け入れるのも、これだけ取り出せば(程度にもよりますが)そんなに難しくありません。
大きな問題は、顧客満足最優先の姿勢が、会社の利益最大化と多くの場合対立する事実です。
物事を単純化して言ってしまうと、前述の@ITの記事のように、愚直にアジャイル宣言に従うとビジネスがわかっていない、と烙印を押されかねません。もっと単純化して言ってしまえば、こういう開発者は会社で出世できません。
アジャイル開発と(会社)利益の追求は、両立可能なんでしょうか。未だに答えがでません。いや、答えがでないは嘘です。会社利益を考えれば考えるほどアジャイル開発から離れざるをえない、という自明な答えを前に、否定したい気持ちをどう整理するかの葛藤が現実です。
最近のコメント