木曜日, 4月 16, 2009

[Solr] Nutchでサイトクロール

Solrを使ってサイトクロールを行う方法が、公開されていたので、

やってみた。

Nutchはウェブスパイダーとしてのクロール機能を提供している。内部に分散ファイルシステムたるHadoopを持っていのだが、今回はこれは使わない方法(のようだ)。

- - - -

1. Nutchを<a href="http://hudson.zones.apache.org/hudson/job/Nutch-trunk/">ダウンロード</a>し、解凍する。

 tar xzf apache-nutch-1.0.tar.gz

2. Solrの設定を行う

Nutchの中にはschema.xmlなどSolrを連携して使うためのサンプルの設定ファイルが含まれています。

a. schema.xmlの配置
apache-nutch-1.0/conf to directory apache-solr-1.3.0/example/solr/conf

b. “content”フィールドの設定変更

<field name=”content” type=”text” stored=”true” indexed=”true”/>

c. クローラ用リクエストハンドラの作成

以下をsolrconfig.xmlに追記します。

<requestHandler name="/nutch" class="solr.SearchHandler" >
<lst name="defaults">
<str name="defType">dismax</str>
<str name="echoParams">explicit</str>
<float name="tie">0.01</float>
<str name="qf">
content^0.5 anchor^1.0 title^1.2
</str>
<str name="pf">
content^0.5 anchor^1.5 title^1.2 site^1.5
</str>
<str name="fl">
url
</str>
<str name="mm">
2&lt;-1 5&lt;-2 6&lt;90%
</str>
<int name="ps">100</int>
<bool hl="true"/>
<str name="q.alt">*:*</str>
<str name="hl.fl">title url content</str>
<str name="f.title.hl.fragsize">0</str>
<str name="f.title.hl.alternateField">title</str>
<str name="f.url.hl.fragsize">0</str>
<str name="f.url.hl.alternateField">url</str>
<str name="f.content.hl.fragmenter">regex</str>
</lst>
</requestHandler>

3. Solrを起動しておきます。

cd apache-solr-1.3.0/example
java -jar start.jar

4. Nutchの設定を行います。

a. apache-nutch-1.0/confにあるnutch-site.xmlの中身を以下のものにまるっと入れ替えます。
ここでは、クローラの名前や、有効化するプラグイン、ドメイン単位でみたときの最大同時接続数などを指定します。

<?xml version="1.0"?>
<configuration>
<property>
<name>http.agent.name</name>
<value>nutch-solr-integration</value>
</property>
<property>
<name>generate.max.per.host</name>
<value>100</value>
</property>
<property>
<name>plugin.includes</name>
<value>protocol-http|urlfilter-regex|parse-html|index-(basic|anchor)|query-(basic|site|url)|response-(json|xml)|summary-basic|scoring-opic|urlnormalizer-(pass|regex|basic)</value>
</property>
</configuration>

b. apache-nutch-1.0/confにあるregex-urlfilter.txtの中身を書き換えます。

-^(https|telnet|file|ftp|mailto):
 
# skip some suffixes
-\.(swf|SWF|doc|DOC|mp3|MP3|WMV|wmv|txt|TXT|rtf|RTF|avi|AVI|m3u|M3U|flv|FLV|WAV|wav|mp4|MP4|avi|AVI|rss|RSS|xml|XML|pdf|PDF|js|JS|gif|GIF|jpg|JPG|png|PNG|ico|ICO|css|sit|eps|wmf|zip|ppt|mpg|xls|gz|rpm|tgz|mov|MOV|exe|jpeg|JPEG|bmp|BMP)$
 
# skip URLs containing certain characters as probable queries, etc.
-[?*!@=]
 
# allow urls in foofactory.fi domain
+^http://([a-z0-9\-A-Z]*\.)*lucidimagination.com/
 
# deny anything else
-.

5. 初期URLリスト(クロール起点)ファイルを作成します。

mkdir urls
echo "http://www.lucidimagination.com/" > urls/seed.txt

6. 初期URLのページをクロールしてNutchのcrawldbに格納します。

bin/nutch inject crawl/crawldb urls

konpyuta:~/work/nutch tf0054$  bin/nutch inject crawl/crawldb urls
Injector: starting
Injector: crawlDb: crawl/crawldb
Injector: urlDir: urls
Injector: Converting injected urls to crawl db entries.
Injector: Merging injected urls into crawl db.
Injector: done
konpyuta:~/work/nutch tf0054$

7. 取得したページを解析してコンテンツを抜き出します。

bin/nutch generate crawl/crawldb crawl/segments

konpyuta:~/work/nutch tf0054$ bin/nutch generate crawl/crawldb crawl/segments
Generator: Selecting best-scoring urls due for fetch.
Generator: starting
Generator: segment: crawl/segments/20090416032246
Generator: filtering: true
Generator: jobtracker is 'local', generating exactly one partition.
Generator: Partitioning selected urls by host, for politeness.
Generator: done.
konpyuta:~/work/nutch tf0054$

上のコマンドで、crawl/segments以下に新たなクロール対象のディレクトリを作成します。 that at this point contains files that store the url(s) to be fetched. In the following commands we need the latest segment dir as parameter so we’ll store it in an environment variable:

export SEGMENT=crawl/segments/`ls -tr crawl/segments|tail -1`

クロールを開始します。

bin/nutch fetch $SEGMENT -noParsing

konpyuta:~/work/nutch tf0054$ bin/nutch fetch $SEGMENT -noParsing
Fetcher: Your 'http.agent.name' value should be listed first in 'http.robots.agents' property.
Fetcher: starting
Fetcher: segment: crawl/segments/20090416032246
Fetcher: threads: 10
QueueFeeder finished: total 1 records.
fetching http://www.lucidimagination.com/
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-finishing thread FetcherThread, activeThreads=1
-activeThreads=1, spinWaiting=0, fetchQueues.totalSize=0
-activeThreads=1, spinWaiting=0, fetchQueues.totalSize=0
-finishing thread FetcherThread, activeThreads=0
-activeThreads=0, spinWaiting=0, fetchQueues.totalSize=0
-activeThreads=0
Fetcher: done
konpyuta:~/work/nutch tf0054$

コンテンツをパースします。

bin/nutch parse $SEGMENT

konpyuta:~/work/nutch tf0054$ bin/nutch parse $SEGMENT
konpyuta:~/work/nutch tf0054$

Then I update the Nutch crawldb.
updatedb コマンドを使うと、先にとってきたページのパースと、もうパースされて見つかっているURLページの取得をパイプライン的に並行して行わせることができます。なお、Nutchは取得した各ページの状態を覚えているため、同じページを何度も取得しに行ってしまうことはありません。

bin/nutch updatedb crawl/crawldb $SEGMENT -filter -normalize

konpyuta:~/work/nutch tf0054$ bin/nutch updatedb crawl/crawldb $SEGMENT -f
ilter -normalize
CrawlDb update: starting
CrawlDb update: db: crawl/crawldb
CrawlDb update: segments: [crawl/segments/20090416032246]
CrawlDb update: additions allowed: true
CrawlDb update: URL normalizing: true
CrawlDb update: URL filtering: true
CrawlDb update: Merging segment data into db.
CrawlDb update: done
konpyuta:~/work/nutch tf0054$

これまでが、クロールの1サイクルとなります。

8. linkdbを作る

bin/nutch invertlinks crawl/linkdb -dir crawl/segments

konpyuta:~/work/nutch tf0054$ bin/nutch invertlinks crawl/linkdb -dir crawl/segments

LinkDb: starting
LinkDb: linkdb: crawl/linkdb
LinkDb: URL normalize: true
LinkDb: URL filter: true
LinkDb: adding segment: file:/Users/tf0054/work/nutch-2009-04-15_04-01-57/crawl/segments/20090416032246
LinkDb: done
konpyuta:~/work/nutch tf0054$

9. 全セグメントからSolrにコンテンツを送る

bin/nutch solrindex http://127.0.0.1:8983/solr/ crawl/crawldb crawl/linkdb crawl/segments/*

10. Solrにて検索可能となったか確認する。

http://127.0.0.1:8983/solr/nutch/?q=solr&amp;version=2.2&amp;start=0&amp;rows=10&amp;indent=on&amp;wt=json

- - - - -

水曜日, 4月 15, 2009

[Scala] スクリプト実行!

Javaで要求される杓子定規な、というか精緻な記述が省けるだけでもScalaを利用する価値はあるというものだが、さらにスクリプト実行(コンパイルして.classを作ってからじゃなく)できるとその価値はより高くなる。

以下、Windowsでスクリプト実行する場合(test.batなどとして保存されることを想定)。
::#!
@echo off
call c:\scala-2.7.4.final\bin\scala %0 %*
goto :eof
::!#

class HelloFunction {
def apply() = "hello"
def apply(name: String) = "hello " + name
}

// メソッド省略の例
val hello = new HelloFunction
println(hello()) // => "hello"
println(hello("Dean")) // => "hello Dean"

// コマンドライン引数処理の例
for(i <- 1 to (args.length)){
print(i + ",");
}

日曜日, 4月 12, 2009

[Java] SenよりもGoSen?

ちょっと前に見たSenは、しかしバグ付きだという噂だし、どうしたものかと思っていたら、GoSenというのもあるらしい。

PerlやJCLからの依存性を排除したとのことだが、しかし、これも本家のURLがNotFoundで、、どうもJavaでこの手のアプリは保守するのが面倒になるものなのか(CMeCabの中にあるような、辞書不要のタイプもある)。


書きながら調べていたら、早速(Senよか治ってるようだけど)バグ情報も。あとLucene対応の書換えについて。

土曜日, 4月 11, 2009

[Life] GAE/Javaとは

Javaのアカウントが来たので、Liftの稼働実験をしつつ、@ITの記事を読む。
昨日まで「負荷による拡張はgoogleさんがよしなにやってくれる」という言説の意味(どうやって水平分散に回せているのか)が、まったく分からなかったのだけど、やっと理解。
シングルスレッドだからですね。
ウェブからの各アクセスを一筆的に考えると、確かに途中で抜けられたりしなければ、筐体が分かれてても(2本の干渉が無いから)ざーっと勝手に流れて行って問題ないんですね。。なるほど。というか確かに。

追伸:
面白い潜入調査をしている方がいた。あと、mavenからの操作も出来るようになった。

木曜日, 4月 09, 2009

[Lift] derbyの中を調べる

Liftの例(todo)では、標準ではapacheのderbyが使われており、この中にテーブルなどが自動生成される。この、自動生成されたテーブル定義やらを見る方法を調べたのでメモ。

D:\work\Scala\todo>"d:\Documents and Settings\00962724\デスクトップ\db-derby-10.5.1.1-bin\bin\ij.bat"
ij バージョン 10.5
ij> connect 'jdbc:derby:d:\work\scala\todo\lift_example';
ij> describe users;
COLUMN_NAME |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL&
------------------------------------------------------------------------------
ID |BIGINT |0 |10 |19 |AUTOINCRE&|NULL |NO
FIRSTNAME |VARCHAR |NULL|NULL|32 |NULL |64 |YES
LASTNAME |VARCHAR |NULL|NULL|32 |NULL |64 |YES
EMAIL |VARCHAR |NULL|NULL|48 |NULL |96 |YES
LOCALE |VARCHAR |NULL|NULL|16 |NULL |32 |YES
TIMEZONE |VARCHAR |NULL|NULL|32 |NULL |64 |YES
PASSWORD_PW |VARCHAR |NULL|NULL|48 |NULL |96 |YES
PASSWORD_SLT |VARCHAR |NULL|NULL|20 |NULL |40 |YES
TEXTAREA |VARCHAR |NULL|NULL|2048 |NULL |4096 |YES
SUPERUSER |SMALLINT |0 |10 |5 |NULL |NULL |YES
VALIDATED |SMALLINT |0 |10 |5 |NULL |NULL |YES
UNIQUEID |VARCHAR |NULL|NULL|32 |NULL |64 |YES

12 行が選択されました
ij> describe todo;
COLUMN_NAME |TYPE_NAME|DEC&|NUM&|COLUM&|COLUMN_DEF|CHAR_OCTE&|IS_NULL&
------------------------------------------------------------------------------
PRIORITY |INTEGER |0 |10 |10 |NULL |NULL |YES
ID |BIGINT |0 |10 |19 |AUTOINCRE&|NULL |NO
DESC_C |VARCHAR |NULL|NULL|128 |NULL |256 |YES
DONE |SMALLINT |0 |10 |5 |NULL |NULL |YES
OWNER |BIGINT |0 |10 |19 |NULL |NULL |YES

5 行が選択されました
ij> show tables;
TABLE_SCHEM |TABLE_NAME |REMARKS
------------------------------------------------------------------------
SYS |SYSALIASES |
SYS |SYSCHECKS |
SYS |SYSCOLPERMS |
SYS |SYSCOLUMNS |
SYS |SYSCONGLOMERATES |
SYS |SYSCONSTRAINTS |
SYS |SYSDEPENDS |
SYS |SYSFILES |
SYS |SYSFOREIGNKEYS |
SYS |SYSKEYS |
SYS |SYSROLES |
SYS |SYSROUTINEPERMS |
SYS |SYSSCHEMAS |
SYS |SYSSTATEMENTS |
SYS |SYSSTATISTICS |
SYS |SYSTABLEPERMS |
SYS |SYSTABLES |
SYS |SYSTRIGGERS |
SYS |SYSVIEWS |
SYSIBM |SYSDUMMY1 |
APP |TODO |
APP |USERS |

22 行が選択されました
ij> exit
> ;
D:\work\Scala\todo>

木曜日, 4月 02, 2009

[Scala] 遅延評価の例

Scalaで遅延評価。引数の型指定部分で":"の後ろに"=>"を挟み込むことで指示できる(参考)。
#!/bin/bash
exec ~/work/scala/bin/scala "$0" "$@"
!#

def until(f: => Boolean)(p: => Unit) {
while (!f) p
}

var i = 0
until (i > 10) {
print(i + " ")
i += 1
}
println
この例で遅延評価を外す("until(f:Boolean)"とやる)と、
・最初に"i>10(でi=0)"がfalseと評価される
・その結果(false)がuntil関数に渡ってしまう
ため、(trueと渡って来たものを再評価できるわけもなく)無限ループに陥ってしまいます。

なお、"(p: => Unit)"もその意味では遅延評価の指定がなされている、つまり「関数とは要するに引数付き遅延評価式で」ということで、具体的にはココを"(p:Unit)"とすると、
・1回だけuntilに渡したブロック(printとか)を処理して
・戻値が無い(Unitな)whileが回り続ける(iは1になったが以後そのまま)
状態に陥ってしまう。なのでここでも遅延評価が活躍している(んだと思う)。

月曜日, 3月 30, 2009

[Linux] JMX/REST変換

TomcatのManagerにもJMXProxyがあるのでそれで良いような気はしますが、こんなのもあるようです。
http://code.google.com/p/polarrose-jmx-rest-bridge/

via kwout

ダウンロードからは何も取れないですが、ソースのところをくだるとありそう。

日曜日, 3月 22, 2009

[Life] ScalaでSolrj!

下のソースで、以下条件下にて、
 ・Solr(v1.4-dev/今のtrunk)のサーバ相手に
 ・Solr(v1.3)のsolrjライブラリで
実行すれば、ABROADのスポット情報1件をインターネットから取得してうまく日本語も投入してくれることを確認しました。

なぜv1.4のsolrjを組み込むとうまく動かないのか。。(補足:SOLR-973にタイムリーにはまっていたようで、今updateしたらサーバもsolrjもv1.4で正常動作しました!)


// >\scala-2.7.3.fin\bin\scalac -cp c:\apache-solr-1.3.0\dist\solrj-lib\commons-httpclient-3.1.jar;c:\apache-solr-1.3.0\dist\apache-solr-solrj-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-core-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-common-1.3.0.jar getAB.scala
// >\scala-2.7.3.fin\bin\scala -cp .;c:\apache-solr-1.3.0\dist\solrj-lib\commons-httpclient-3.1.jar;c:\apache-solr-1.3.0\dist\apache-solr-solrj-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-core-1.3.0.jar;c:\apache-solr-1.3.0\dist\apache-solr-common-1.3.0.jar;c:\apache-solr-1.3.0\dist\solrj-lib\commons-logging-1.0.4.jar;c:\apache-solr-1.3.0\dist\solrj-lib\commons-codec-1.3.jar getAB

import java.util.ArrayList;
import java.util.Collection;

import scala.xml.parsing.ConstructingParser;
import scala.io.Source;
import scala.xml.PrettyPrinter;

import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.common.SolrInputDocument;

object getAB {
def main(args : Array[String]) {

var solr = new CommonsHttpSolrServer("http://localhost:8983/solr");
val url = "http://webservice.recruit.co.jp/ab-road/spot/v1/?key=xxx4e359bbbbe6f4&spot=000921";

val data = Source.fromURL(url,"UTF-8");
val elem = ConstructingParser.fromSource(data,true).document().docElem;

var tmp1:String = (elem\"spot"\"description").text;
//var tmp1:String = new PrettyPrinter(80 /*width*/, 2 /*indent*/).format(elem);
//String変数(tmp1)から(UTF8エンコードな)バイトストリームで取り出し(そこから)UTF8のStringを作る
var tmp2:String = new String(tmp1.getBytes("UTF-8"),"UTF-8");
var tmp3:String = new String(tmp2.getBytes("MS932"),"MS932");

//System.out.println( "ORG:\n"+tmp1 );
System.out.println( "UTF8:\n"+tmp2 );
System.out.println( "SJIS:\n"+tmp3 );

var doc1 :SolrInputDocument = new SolrInputDocument();
doc1.addField("id", "id1", 1.0f);
doc1.addField("name", "doc1", 1.0f);
doc1.addField("price", 10);

var doc2 :SolrInputDocument = new SolrInputDocument();
doc2.addField("id", "id2", 1.0f);
doc2.addField("name", "doc2", 1.0f);
doc2.addField("price", 20);
doc2.addField("desc_t", tmp2);

var docs :Collection[SolrInputDocument] = new ArrayList[SolrInputDocument]();
docs.add(doc1);
docs.add(doc2);

solr.add(docs);
solr.commit();
}
}

お恥ずかしくも、Scalaっぽくはまったく無い書きっぷりですが、これでもJavaよりはだいぶ記述量が少ない気がします。

追伸:
 リクルートwebAPIを使うときのキーは、(ソースには)ダミーを入れています。

金曜日, 3月 20, 2009

[Life] ScalaでJSP!

ScalaのXMLサポートを実装した"Burak Emir"さんの書かれた"ScalaでJSP(@Tomcat)"(改題)を参考に。ソースにはantのbuildが付いているので、これを使うと楽に準備できる。私は、

tomcat.home = D:\\apache-tomcat-5.5.27
servlet-api.jar = ${tomcat.home}/common/lib/servlet-api.jar

scala.home = D:\\scala-2.7.2.final
scala-library.jar = ${scala.home}/lib/scala-library.jar
scala-compiler.jar = ${scala.home}/lib/scala-compiler.jar

として実行しました。なお、以下ライブラリは「1フォルダにまるっと集めて、そこにCLASSPATH通してantしてね」とあったのでその通りに。

 ・fjbg.jar(これは何?→何故か入っていなかったのでダウンロード)
 ・tools.jar(JDKの中にあるライブラリ)
 ・scala.jar(不明→scala-compiler.jarをコピーした)

結構すんなり。ScalaでウェブといえばWebFlavorliftまで行ってしまう感がありましたが、これならお手軽ですね。

木曜日, 3月 19, 2009

[Linux] EC2の管理ツール

メモっていたつもりが、書いていなかったので今更ながら。

RightScaleでは、動的にサーバ台数を増やしてゆく仕組み(RightScriptというマクロ的なもので実現する様子)を提供。
そのOSSとしてScalarというのが公開(元は商用)されているので、こっちをカスタマイズするのとどっちが便利か。

でもどちらにせよ"遠い向こうでインスタンスを上げる"というのが普通な世界になってきましたね。

水曜日, 3月 18, 2009

[Java] commons-fileuploadで受け取る

curlを使って、apacheのcommon-uploadで受信できる形で送信する方法。
D:\work\curl-7.16.2>curl -F "name=@test.xml" http://192.168.11.150:20050/uploader

nameのところは何でもよい(参考)。Windows版のcurlはここからダウンロードできます。

金曜日, 3月 13, 2009

[Solr] wgetでPOSTする

以前Solrにデータ投入をする際にはcurlを使っていた(本家でもそうしていた)。
が、これは普通にwgetでも出来るんですね。
wget -q -O - --header "Content-type:text/xml; charset=utf-8" --post-file="/var/tmp/test.xml" http://localhost:20050/apache-solr-1.3.0/update

curlって、いっても標準では入っていない環境も多いので(参考ページ)。

月曜日, 3月 09, 2009

[GoogleMap] マイマップとGoogleMapAPIと

GoogleMapのマイマップ機能はとても使いやすく、ちょろっとしたイベントの地図を作るのにベスト。だけれど、中にルート案内と作者(のマイマップへのリンク)が表示されてしまうのが玉に傷か。
これが嫌なときは、一度rss(georss/マイマップのツールバー、"GoogleEarthで表示"の左隣にある)を経由して、それをAPIで使えばよい、、のだけど、そうするとせっかく変えたアイコンが、全て同じ青いピンのに変えられてしまう様子(でもこれは仕様っぽい)。
うーん。やっぱりキチンと自前ですしょうか。

日曜日, 3月 08, 2009

[MT] カスタムフィールド

MovableType4.1から入ったカスタムフィールドは、エクスポート機能では取り出せない様子。DBのmt_entryテーブルからとろうとしたのだが、バイナリ列で連結されており。。

ただ、入力値は普通に入っているので、Perlなどで丸呑みし、無理やり置き換えは可能。
手動で投入したときは(mt_entry_idの)シーケンス上げを忘れずに。

土曜日, 3月 07, 2009

[Scala] Twitterの移行について

ずいぶん前の話題だが、TwitterのバックヤードScala化に関する記事の要点整理をしてみた。

>>前提

Twitterは、フロントはRailsに依存しており、逆にOffload観点から、キャッシュの失効処理等に、キューイングの仕組みを使った非同期処理が多数あり、それだけデーモンアプリが必要となるシステム構成。

>>なぜ移行?(システム的理由)

RubyはGreenThreadでカーネルスレッドを使うことはできず、プロセッサに依存してしまい、マルチコア環境での性能が出ない。これに対処するため複数プロセスを上げる方向に行くのだが、そうなるとメモリが大量に必要となり、さらにRubyのガベコレ性能が(Javaのそれに比べて)悪いこともあり、限界を感じていた。

(これに対し)JVMは、スクリプト言語が苦手とする長時間動かし続けるデーモンアプリを書く環境として適切。

また、動的型付けにより必要となる「型確認」の計算量が莫大になっていたという問題もあった。たとえば障害復旧時の処理時間が長くなりすぎていた。

JRubyへの移行も考えたが、オリジナルレベルのパフォーマンスは出ないこと、またそもそもRailsが動かなかったことから不採用とした。ただし将来的に再考の余地はあると考えている。

パフォーマンスという観点では、mutableとimmutableに注意すること。JITコンパイラはimmutableなオブジェクト(状態変化がない≒必然的にスレッドセーフとなる)であれば、最適化してゆくことができる。

>>なぜ移行?(その他の理由)

これまでのエンタープライズな職場を去ったあと、楽しく書いてゆきたい(表現してゆきたい)という理由から、(書いていてつまらない言語(C++など)を卒業し)Ruby等の高級言語に転向するプログラマをたくさん見てきた。

>>移行してどうだったか

とても上手くいった(性能向上及び動作安定化の観点から)。

静的型付けは、(Rubyでもわざわざ型宣言を使っていた位だから)まったく手間ではなかった。

actor部分とハイスケーラビリティを確保するところでいくつか問題が出たが、致命的なものはまったく無かった(良い意味で想定外)。

actorでの並列処理の記述はクライアントからの接続を受ける部分などを中心に極めて有効であった。

(中を再考している過程で)逆にactorまでは必要とせず、逆にthreadのほうが適している場合もあることが分かった。そしてこのときでも、(actorを)threadに書き戻すことは置換するレベルでありとても簡単だった(書き換えでいうと、普通にlockすればいいだけという場合も)。

いくつかパフォーマンス観点からJavaのクラスを直接利用する場面があったが、このようなことができることもScalaの利点だ。

>>切り替えで気をつけることは

関数型という考え方になれること(メンタリティ)。ただしこれは使っているうちに慣れてくる部分が大きい。その意味でもすぐにビジネスが絡むシステムに使うのではなくスタートアップで利用してゆくべき。

(型やその中身ベースでの)パターンマッチを使いこなせることは、効率的記述を行うためにとても重要だ。

IDEがモノによっては(Scalaの)サポートが完全ではないため注意が必要。TwitterではIntelliJとEmacsのそれを使っている。

インタプリタではなくcompile-deployが必要になることも、(慣れの問題かもしれないが)いらいらさせる原因となりうる。この点はProjectごとにケアが必要だとはいえ、JavaRebelを使えば解決できる。

>>その他

Scalaを選択する決断をするまでには煩悶してきた。でも(Rubyを使ってきた我々が)C++などの中級言語に移行することは、とても大きなリスクを負うことになり、かつ困難を伴うと判断した。

2009年度内には、メインどころのトラフィックを稼いでいるAPIをScalaベースに切り替える予定。

日曜日, 2月 22, 2009

[Perl] デーモンプログラムを書くには

今まで全く読んだ事がなかった"perlfaq8"より。

psコマンドなど、外部から見えるコマンドラインを実際に書き換えるには、$0変数を書き換える。

例えばsendmailのようなデーモンプログラムは以下ように状態を設定する:
$0 = "orcus [accepting connections]";

なるほどー。そんなことができるんだ。。

ちなみに、デーモンプログラムというかapache的なデーモンを書くためには、Parallel::Preforkがとても便利です(中で使われているProc::Wait3というのは初めて知りました)。

金曜日, 2月 20, 2009

[Life] XMLをコマンドラインで

GUIが使えるときは、折り畳めるエディタを使えばよいのだが、ターミナル操作のときにXMLで書かれたファイルの記述を確認するのは、とても難儀する。。。

と思っていたらxpathコマンドを発見。以下のように使う。
D:\apache-solr-trunk\example\solr\conf>xpath schema.xml "(//fieldtype|//fieldType)/@name"


これにより、この例ではsolrのスキーマに設定されいてるフィールドに与えられる型一覧を取得することが出来る。便利!

木曜日, 2月 19, 2009

[Java] Senのバグ

Javaで形態素解析をするときに、使われるSenだが本家からダウンロードできるオリジナルソースはバグ付き。これはgnarlさんのページに修正方法が詳しく記載されている様子。

土曜日, 2月 14, 2009

[Linux] googleクローラはJavascriptが読める

googleのクローラがJavascriptに対応していそう、という記事を発見。
http://searchengineland.com/an-update-on-javascript-menus-and-seo-16060

via kwout

常識でしょうか。私は知りませんでした。。当然の流れとは言え、すごいことだと思います。Flashが読まれるようになったことは知っていて、こちらは奏すべきだろうと思いましたが。。

金曜日, 2月 13, 2009

[Flash] PixelBlender

Flasherな人にしたらいまさらな話なのだと思うが、PixelBlenderがすごい。

画像にぷるん、とした動きをさせたいと思っていたのが、もろできるようです。
というかこういうのを思いのままに作れるというのであれば(センスは相当必要とされそうだけど)、かなり勉強する価値ありそう。

日曜日, 1月 25, 2009

[Linux] Kirin

相当今更感があるのですが、Kirinという画像のリサイズなどが行える、画像変換のWebAPIを使ってみました。アプリキーをもらってから使うものなのですが、、説明に書かれている"呼び出し元サーバ名"って、、変換したい元画像が置いてあるサイトのドメイン名を書くのですね。。。うーん。
http://kirin.tatamilab.jp/

via kwout

たまたまGIF画像のリサイズをしてみたので気がついたのですが、戻しはJPGなんですね(JPGのコメントにはしっかり"Kirin Library 1.11 2009/01/25 0"と入っていました)。

火曜日, 1月 20, 2009

[Scala] TwitterもScalaで

Twitterでユーザ間のメッセージ送受信を実装するために使っている(のであろう)、キューイングシステムが、Rubyから(!)いつのまにかScalaにて書き直された、とのこと。その上これはソースも公開されているので、ぜひ勉強がてら読んでみたい(最近githubが増えてきましたね9。

[Perl] 携帯サイトのアクセス分析!

MovableTypeを携帯対応する一番簡単な方法は、mt4iなわけですが、このアクセス解析をapacheログでやるのも面倒に思いました。
なので、最近出たGA4Kという、GoogleAnalyticsに携帯アクセスを流すPHPライブラリ(まぁ原理的にはココでも紹介されているとおり、たいしたことはないのですが)を、Perlモジュールに作り変えてみました(以下ソース。ウェブプロパティID(utmac)とウェブサイトURL(utmhn)は書き換えてください!)。
#
# This code is test module for k-tai web site (ex mt4i)
#
package Onamon;

sub accessGoogleAnalystics{

use Sys::Syslog;
require HTTP::Request;
require LWP::UserAgent;

my $utmac = 'UA-179xxxx-2';
my $utmhn = 'http://onamon.com';
my $utmn = 1000000000 + rand(9999999999 - 1000000000);
my $cookie = '';
my $uservar = '';
my $random = 1000000000 + rand(2147483647 - 1000000000);
my $today = time();
my $referer = $ENV{'HTTP_REFERER'};
my $utmp = $ENV{'REQUEST_URI'};

if($ENV{'HTTP_X_UP_SUBNO'}){
$uservar = $ENV{'HTTP_X_UP_SUBNO'};
}elsif($ENV{'HTTP_X_DCMGUID'}){
$uservar = $ENV{'HTTP_X_DCMGUID'};
}elsif($ENV{'HTTP_X_JPHONE_UID'}){
$uservar = $ENV{'HTTP_X_JPHONE_UID'};
}
$cookie = $uservar;

my $urchinUrl = 'http://www.google-analytics.com/__utm.gif?utmwv=1&utmn='.$utmn.'&utmsr=-&utmsc=-&utmul=-&utmje=0&utmfl=-&utmdt=-&utmhn='.$utmhn.'&utmr='.$referer.'&utmp='.$utmp.'&utmac='.$utmac.'&utmcc=__utma%3D'.$cookie.'.'.$random.'.'.$today.'.'.$today.'.'.$today.'.2%3B%2B__utmb%3D'.$cookie.'%3B%2B__utmc%3D'.$cookie.'%3B%2B__utmz%3D'.$cookie.'.'.$today.'.2.2.utmccn%3D(direct)%7Cutmcsr%3D(direct)%7Cutmcmd%3D(none)%3B%2B__utmv%3D'.$cookie.'.'.$uservar.'%3B';

my $ua = LWP::UserAgent->new;
my $request = HTTP::Request->new(GET => $urchinUrl);
if ($ENV{'HTTP_ACCEPT_LANGUAGE'}) {
$request->header('Accept-language' => $ENV{'HTTP_ACCEPT_LANGUAGE'});
}
if ($ENV{'HTTP_USER_AGENT'}) {
$request->header('User-Agent' => $ENV{'HTTP_USER_AGENT'});
}
my $response = $ua->request($request);

openlog(__FILE__, 'cons,pid', 'local4');
if ($response->is_success) {
syslog('debug', 'OK('
.$ENV{'REQUEST_URI'}
.'^'.$ENV{'HTTP_USER_AGENT'}
.'^'.$ENV{'HTTP_X_DCMGUID'}
.')'
);
} else {
syslog('debug', 'NG');
}
closelog();
}
1;
汚い、というか何も考えていないソースで恥ずかしいですが、一応。mt4iに適用するなら、mt4i.cgiと同じディレクトリに上記ソースをOnamon.pmとして保存し、mt4i.cgiの最初のほうに、
~略~
use FindBin qw($Bin);
use List::Util qw(first);
use HTTP::Date;
use CGI::Carp qw(fatalsToBrowser);

# ★ここから
use Onamon;
if($ENV{'REQUEST_URI'} !~ /(png|jpg)$/){
Onamon::accessGoogleAnalystics();
}
# ★ここまで

my $bin;
my $log_pl;
our %cfg;

BEGIN {
~以下略~
と足します。お名紋贈り物ブログに適用してみたのですが、、果たして動くことやら。

日曜日, 1月 18, 2009

[Perl] CTPP2テンプレートエンジン

CPANのPerlモジュールがひたすらupdateされていて、頑張っている感のあるテンプレートエンジン(C++で書かれていて各種言語でバインディング可能なもの)。
http://freshmeat.net/projects/ctpp2/

via kwout

気になるのでメモ(Perlのモジュールはコチラ)。

土曜日, 1月 10, 2009

[Flash] JPEG格納フォーマット

以下ページに良くまとまっている。
http://pwiki.awm.jp/~yoya/?Flash/JPEG

via kwout

こられとやまさんページのFlashをswfmillで解析中(珍しくFlashLite1.1で出来たスライドショー)。

月曜日, 1月 05, 2009

[Life] XMLファイルをきちんと扱う

最近ミドルウェアの設定ファイルをXMLで書かなくてはならないことが多くなってきた。
可読性が意外と低いので、きちんとXMLを解釈して折りたたみなどができるエディタを探していたのだが、とりあえずjEditでできることまでわかった。

Pluginが1つ必要(その名もXMLというやつ)なのだが、PluginマネージャというGUIでさくっとインストールできる。

希望していた動きをするので、今しばらくはこれで行こうと思う。

月曜日, 12月 29, 2008

[Solr] 日本語解析には

cmecab-java、本当はMeCabをJavaから使うためのバインディング(本家のmecab-javaをSWIG使わず実装したもの)なのだけど、中にSolr用のファクトリクラスが含まれていることに注目すべし。
http://code.google.com/p/cmecab-java/

via kwout

Java記述がv1.6系向けで、まだv1.5系の場合は少し書き換えが必要になる(MecabExceptionで2つメソッドを消した/string型のisEmptyをnull比較に変更)のですが、なんとか無事Solr(v1.3)から使えるようになりました。

あ、あとMacでコンパイルする場合、Makefileが合わないのでシアノさんのページを見ながら書き換えること、また、標準Javaのエンコード指定が何故かSJISなので、"-D file.encoding=UTF-8"とする必要があります。

参考:ハタさんのブログ

日曜日, 12月 21, 2008

[life] ソースをハイライト

ブログにソースを張るときに。
http://uwanosora.xrea.jp/2008/06/web.html

via kwout

金曜日, 12月 19, 2008

[Solr] SpellCheckComponent

Solrには「もしかして検索」を実装するのに使えそうなSpellCheckComponentというコンポーネントがあるが、日本語は何故か使えない様子(出所はIBMの開発者向けページ/いつも質が高く関心する)。
Lukeで見るところ、SpellCheck用フィールドのトークナイザをMeCabにしているから、当然キチンとword及びstart3なんかにも、想定した切り方で入っているようだが。。
問題はクエリ側か?

参考:LingPipe, Wiki

日曜日, 12月 14, 2008

[Life] userchrome.jsの練習で

すばらしい先達。これから(も)勉強できそう。
clipped from www.code-404.net
Copy URL Lite+
 blog it

水曜日, 12月 03, 2008

[Life] XULの情報元!

Firefoxの拡張(userChromeのだけど)を改訂したくて、XULのチュートリアルを探していた。しかしそもそもマニアックなので書籍など期待できないな、と思っていたら、、、なんとウェブ上にとてもしっかりとした情報が公開されていました。
http://piro.sakura.ne.jp/xul/doc/tutorial/

via kwout

本当に、こういう活動には頭が下がります(しかし、本家のチュートリアルも日本語で充実してました。もう実は至れり尽くせり!?)。
あれ?でもFirefox2と3で少しは違うのかな。

火曜日, 12月 02, 2008

[S3] junglediskの次

CUIのツールを探していて、s3cmdが便利そう。pythonで書かれている。
http://s3tools.logix.cz/s3cmd

via kwout

"--configure"で設定ファイルを書くウイザードになる親切設計。

月曜日, 12月 01, 2008

[Linux] apacheの内部構造

1999年当時のものと古いですが、apacheの内部構造が説明された論文(?)を見つけました。
https://styx.uwaterloo.ca/~oadragoi/cw/CS746G/a2/acc.html

via kwout

日曜日, 11月 30, 2008

[PgSQL] セッションの切断方法

PostgreSQLは、DBサーバとしてクライアントのセッションについてタイムアウトをかけない。このため、さすがにちょっとセッションが多すぎるな、とDBAが思ったとして、今度はセッションを切断する方法がよくわからない。。
と思ったら、管理者向け関数の中にあるpg_cancel_backend(pid int)というやつが役に立つようだ。これをpsqlからざくっと発行すれば、セッションは殺せるらしい(PostgisのMLより)。

SELECT pg_cancel_backend(5220);


なるほどね。

水曜日, 11月 26, 2008

[Solr] jQueryのSolrプラグイン

すばらしい!

月曜日, 11月 24, 2008

[Java] 性能試験のときなどに

Javaアプリは、性能に関係するパラメータが多すぎてよくわからない。なので試験時に如何にうまく、多くの情報を得て分析できるかが肝要だと思います。
これまで、JVMの情報をSNMPで取れることは知っていて、これを細々とZABBIXでグラフ化したり、少し前からzapcatを知ったのでそれを用いてTomcatのスレッド挙動を見たりしていました。
そして今日、今更ながらzapcatのzipファイルの中に「Javaテンプレート」が入っていることを発見しました。これは偶然、ファイルディスクリプタの消費って取れないのかな?と調べていた中で見つけました。
早速入れてみたのですが、なんかいっぱい取れすぎて、、でもこういう、先人の知恵(?)から学ぶことは大きいので、ちょっとづつ内容を確認してゆこうと思います。

でも、、灯台元暗しというか。。

木曜日, 11月 20, 2008

[Life] userChrome

httpヘッダに入ってくるデバッグ用の拡張httpヘッダを探すのに疲れたので、、LiveHeadersなんかを使わず画面上にそれとなく、そのデバック情報を表示してくれるような機能を、(今更ながら)Firefoxの拡張として、userChromeを使って書いてみた。画面上はで想定する動きになったので、次はステータスバーかメニューにoff/onスイッチを付けたい。

そもそもJavascriptが苦手ですが、意外に書けるもので、調子にのってこの苦手も克服できるよう、Javascriptの開発環境を整備してみようか、と考えています。

今回はuserChromeを使ってみたのですが、それより前からある(?)JavascriptActionsというやつと、どっちがどう(良い)のか。知りたいです。

火曜日, 11月 18, 2008

[Life] MS-Accessの調査で

MS-Accessから、クエリ名とSQLの一覧を取得するVBAスクリプト(Cドライブ直下にlog.txtという名前でファイルアウトします)。

Option Compare Database

Public Sub MyQueryName()

On Error GoTo エラー

    Dim Cat As ADOX.Catalog
    Dim viw As ADOX.View
    Dim pcd As ADOX.Procedure
    Dim strmsg As String
    
    ' ファイルハンドルオープン
    Open "C:\log.txt" For Output As #1

    Set Cat = New ADOX.Catalog
    Cat.ActiveConnection = CurrentProject.Connection 'カレントデータベースに接続
    
    For Each viw In Cat.Views ' --- A
        strmsg = strmsg & vbNewLine & "[v] " & viw.Name & "^" & viw.Command.CommandText
    Next viw
    
    For Each pcd In Cat.Procedures ' --- B
        If Left(pcd.Name, 1) <> "~" Then ' --- C
            strmsg = strmsg & vbNewLine & "[p] " & pcd.Name & "^" & pcd.Command.CommandText
        End If
    Next pcd
    
    Print #1, strmsg
    ' ファイルハンドルクローズ
    Close #1
    
    MsgBox "end."
    Set Cat = Nothing
    
    Exit Sub
    
エラー:
    
    MsgBox Err.Number & vbNewLine & Err.Description, vbCritical
    Exit Sub

End Sub

土曜日, 11月 15, 2008

[Solr] Normとは

Normとはノルムと読み、(Luceneや)Solrでは、検索対象文章の重要度(例/一覧表示するときなど)を決める要素のこと。

たとえばLength-Nornとは「各単語が含まれている文章が長い場合と、短い文章である場合は、後者のほうが(その単語が)、当該文章において重要である(≒その文章の特徴をあらわすものである可能性が高い)」ということを表現する情報のこと。

これ以外に、各文書や(その中の)フィールドがそれぞれ指定されうるブースト値も、この中に含まれます。

なお、よく混同される単語にNormalize(ノーマライズ/Normってこの略かと思いがち)があり、これは広くは正規化処理のことで、こと検索エンジンの世界(?)では、文章を格納するとき(後で使いやすいよう)、半角カナ→全角カナ、だったり、全角アルファベットを半角のそれに統一する処理をいいます。

。。。と調べようと思っていたら、Luceneのスコアリング解析というドンピシャなまとまったpdfが公開されていた。

木曜日, 11月 13, 2008

[Life] scala入門

IBMのページ以外あまり見当たらなかった資金投入された(?)Scalaのページが、日経にもありました。
http://itpro.nikkeibp.co.jp/article/COLUMN/20080613/308019/?ST=develop

via kwout

しかも、結構前からの連載ものです。

日曜日, 11月 02, 2008

[Solr] ロールバック機能!

商用の検索エンジンでもあまり使えない、rollback機能が本家にコミットされました。
論理障害、物理障害を考えるとき、この機能追加はきわめて意味深いと思われます!

木曜日, 10月 30, 2008

[Linux] ReriteRule

いまさらですが、apacheでRewriteしたい+ネームバーチャルを使っている場合、各<VirtualHost>ディレクティブの中で、"ReriteEngine On"ってやらないといけないんですね。。
知りませんでした!

日曜日, 10月 26, 2008

[Linux] lshell

共有環境などでよくあることとして、シェルアクセスを一部許したい、ということがあるが、なかなかうまく設定できるものが少ない(rbashとか標準でついているので便利ではありますが)。このとき、lshellというのがよさそう。
http://sourceforge.net/projects/lshell/

via kwout

木曜日, 10月 23, 2008

Mantisのセキュリティバグ

登録したバグ情報の一部が、アカウントのない人から見られるようです。
本家では修正されているので、個別に対応するのが吉です。

金曜日, 10月 10, 2008

[Scala] jarファイルで実行

Scalaで作ったclassを、OfficeTakeoさんの記事を参考にしながら、なんとなくjarファイルにして、なんとなく実行するところまでやってみた。
D:\work\Scala>jar cvf webProxy.jar webProxy.*
マニフェストが追加されました。
webProxy.class を追加中です。(入 = 596) (出 = 445)(25% 収縮されました)

D:\work\Scala>java -classpath ..\..\scala-2.7.2.RC2\lib\scala-library.jar;jakarta-oro-2.0.8.jar;.;libhttpd.jar webProxy
2008-11-03 11:36:17 thread0 [127.0.0.1] : /pacServer => (200) class : "pacServer"
2008-11-03 (月) 23:36:17.281 127.0.0.1 192.168.10.193
~snip~

でも"-jar"とかなんで要らないんだろう?Javaは本当に良く分からないことばかりです。

月曜日, 10月 06, 2008

MantisからTracへ?

添付ファイルは移らないようだけど、いちおう移行スクリプトはある様子。
でもMySQLだけ対応なんですかね。

土曜日, 9月 06, 2008

[Solr] DataImportHandler

Solrのv1.3がそろそろ公開されるか、という段階。で、そのお試しをしている中で、注目なのがDataImportHandler
データベースからSolrへのデータフィードを簡単にしようというところから始まったようだが、例題にあるようにHTTP経由でのデータ取込みがサポートされており、、、これをうまく拡張利用すれば簡単なロボット機能が作れそう(HTMLタグの削除は簡単そうだし)。

RSSの例題を試すまでの手順をメモ。
・Solr本体をダウンロードして展開(今はRC2)
・例題用のSchema.xmlなどが入ったexample/example-DIHがあることを確認
・Solr本体のexample/conf以下に、example-DIHディレクトリ内のrss/以下をコピー(上書き)
・exampleのところで"java -jar start.jar"
・(稼動確認)ブラウザから"http://xxx:8983/solr/dataimport"にアクセス
・(取込指示)ブラウザから"http://xxx:8983/solr/dataimport?command=full-import"にアクセス
・(動作確認)ブラウザから"http://xxx:8983/solr/dataimport"にアクセス(statusMessagesが追加されてるハズ)
・(結果確認)ブラウザから"http://xxx:8983/solr/select/?q=NASA&version=2.2&start=0&rows=10&indent=on&hl=on&hl.fl=description"にアクセス(このときNASAで検索した)
・ちなみにdelta-importとすると差分更新ができるみたい

仕組みの絵もWikiにありますがかなり考えられたつくりで、


transformerというのを指定すると、例えばDBなりWebから取り込んだデータを、よしなに加工してからSolrにフィードすることができ、そしてこのtransformerに指定する関数は、、1.6系のJavaであればJavascriptなど、別な言語が使えるそうです。至れり尽くせり。

月曜日, 9月 01, 2008

[Scala] CJKでも十分?(SpanScorer)

SpanScorerというので、確かにCJK利用時のハイライタが改善された。

◆SpanScorerの実行例(○)
D:\scala-2.7.0-final\bin\test>..\scala -classpath .;lucene3\lucene-core-2.4-dev.jar;lucene3\lucene-highlighter-2.4-dev.jar;lucene3\lucene-analyzers-2.4-dev.jar HighlightCJKSpan
このプログラムは酒造で合資の会社である、<B>酒造合資</B>会社の事業所で作成されました

◆QueryScorerの実行例(×)
D:\scala-2.7.0-final\bin\test>..\scala -classpath .;lucene3\lucene-core-2.4-dev.jar;lucene3\lucene-highlighter-2.4-dev.jar;lucene3\lucene-analyzers-2.4-dev.jar HighlightCJKQuery
このプログラムは<B>酒造で合資</B>の会社である、<B>酒造合資</B>会社の事業所で作成されました

Javaが書けないのでScalaで(ソースは以下)。

import org.apache.lucene.analysis._;

import org.apache.lucene.analysis.cjk._;

import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight._;

import java.io._;

object HighlightCJKSpan {
val CONTENT = "このプログラムは酒造で合資の会社である、酒造合資会社の事業所で作成されました";
val QUERY_STRING = "酒造合資";
val F = "f";
//var analyzer: Analyzer = new NGramAnalyzer(1,3);
var analyzer: Analyzer = new CJKAnalyzer();

def main(args: Array[String]) {
try{
var qp :QueryParser = new QueryParser( F, analyzer );
var query :Query = qp.parse( QUERY_STRING );

//var scorer :Scorer = new QueryScorer( query, F );
var tokenStream :TokenStream = analyzer.tokenStream(F, new StringReader(CONTENT));
var scorer :SpanScorer = new SpanScorer( query, F, new CachingTokenFilter(tokenStream));

// println(tokenStream);
/*
var token :Token = tokenStream.next();
while(token != null){
println(token.termText());
token = tokenStream.next();
}
*/

var h :Highlighter = new Highlighter( scorer );
println( h.getBestFragment( analyzer, F, CONTENT ) );
} catch {
case e:StringIndexOutOfBoundsException => ()
case e:Exception => {
e.printStackTrace
}
} finally {
// println("FINALLY");
}
}
}

nagaShimaさんのページを参考にさせて頂きました。

金曜日, 8月 29, 2008

[Scala] Luceneのハイライタ(NGramTokenizer)

NGramTokenizerをScalaでやってみました。

import org.apache.lucene.analysis.Analyzer;

import org.apache.lucene.analysis.ngram.NGramTokenizer;

import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.TextFragment;

import java.io.Reader;

object HighlightRunner {
val CONTENT = "東京特許許可局";
val QUERY_STRING = "許可";
val F = "f";
var analyzer: Analyzer = new NGramAnalyzer(1,3);

def main(args: Array[String]) {
try{
var qp :QueryParser = new QueryParser( F, analyzer );
var query :Query = qp.parse( QUERY_STRING );
var scorer :Scorer = new QueryScorer( query, F );
var h :Highlighter = new Highlighter( scorer );
println( h.getBestFragment( analyzer, F, CONTENT ) );
} catch {
case e:StringIndexOutOfBoundsException => ()
case e:Exception => {
e.printStackTrace
}
} finally {
// println("FINALLY");
}
}
}

// http://blog.goo.ne.jp/13th-floor/e/f694fdb1319134b40e4dee5ed8c15a92
class NGramAnalyzer(minGram:Int, maxGram:Int) extends Analyzer {
def tokenStream(fieldName:java.lang.String, reader:java.io.Reader): org.apache.lucene.analysis.TokenStream =
new NGramTokenizer(reader, minGram, maxGram);
}

木曜日, 8月 28, 2008

[Scala] Luceneのハイライタ(N-gram×)

全文検索エンジンLuceneの実験。
公開されていた例(≒N-gramでHighlighterがうまく動かない)をScalaでリライトしてみた。
- - - -
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.Scorer;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.TextFragment;

object HighlightRunner {
val CONTENT = "ひふみひふみひふみひふみひひふひふみろひふみろ";
val QUERY_STRING = "ひふみひふみ";
val F = "f";
var analyzer : Analyzer = new CJKAnalyzer();
def main(args: Array[String]) {
try{
var qp :QueryParser = new QueryParser( F, analyzer );
var query :Query = qp.parse( QUERY_STRING );
var scorer :Scorer = new QueryScorer( query, F );
var h :Highlighter = new Highlighter( scorer );
println( h.getBestFragment( analyzer, F,  CONTENT ) );
} catch {
case e:StringIndexOutOfBoundsException => ()
case e:Exception => {
e.printStackTrace
}
} finally {
}
}
}

木曜日, 8月 21, 2008

[linux] memcachedをsnmpで

AgentXというプロトコルを使うと、既存のsnmpdにアドオンで監視/モニタ対象を増やすことが出来ます。
この方向で、memcachedもAgentXをしゃべられるようにしよう、というpatchがありました。

運用観点でも進歩してくると、ありがたいです。

火曜日, 8月 12, 2008

[linux] DTrace

OpenSolarisで話題のDTrace(PostgreSQLでもサポート)は、いまやLinuxでも使えるんですね(DTrace for Linux)。memcachedもv1.2.6からサポートと書いてあることですし、ぜひ使ってみたいものです。

土曜日, 8月 09, 2008

[Linux] jmxproxy

Javaアプリの性能は、JMXに乗っているならZAPCATZABBIXからモニタリングが可能となりました。ですが、これを自前監視ツール(例/Cacti)などから見るときはどうしたらよいのか、と思っていたら、意外にTomcatそのものに、jmxproxyなんてものが入っていたのですね。
http://snbhsmt.blog110.fc2.com/blog-entry-74.html

snbhsmt_logさんの例 via kwout


これなら、スクリプトでパースするのも簡単そうです。

水曜日, 7月 16, 2008

[Linux] zapcat

Tomcatの監視/モニタリングはどうやるべきか。JVMは昨今snmpをしゃべるので楽だか、Tomcatの中(HTTPコネクタで受けたリクエスト数など)が見られなく困っていたら、ZABBIX(という監視ツール)向けにこれをうまく取得できるサーブレットがあることが分かった。それがzapcat
http://www.kjkoster.org/zapcat/Zapcat_JMX_Zabbix_Bridge.html

via kwout

これを使うと、JMXで取ったデータをZABBIXサーバからのアクセスで見られる様子。JMXは規格としてはとても面白いものだが、いかんせんインフラ屋さんにはあまりにとっつきにくいのが難点だと思う。

火曜日, 7月 08, 2008

[Linux] loadが真夜中に急上昇?

真夜中にレンタルサーバのloadAverageが急上昇し、たまにnamedが落ちるような現象に苛まれていた(1:04に発症)。ZABBIXの監視で見ていても、監視がへんになっていたりする。

これ、logrotateが原因なんですね。普通にVPSじゃないサーバのときには気が付かなかったのですが。。。で良い逃げ策も思いつかなかったのですが、ローテート対象を以下で"100k以上溜まったログ"としてみました(logrotated.confに記述)。
size=100k

これで様子をみようと思います。

木曜日, 7月 03, 2008

[Linux] pg_osmem.py

以前fincoreを使うと、特定のファイルデータがOSキャッシュ上にどれくらい載っているかが調べられることをメモしたが、以下pg_osmem.pyというコマンドが投稿されていた。
http://www.kennygorman.com/wordpress/?p=250

via kwout

出力例などが見られないのでなんともですが(ちなみに、これで使われているpsycopg2というDBコネクタも性能がよいものであるとのことです)。

月曜日, 6月 30, 2008

[Linux] MPXJ

MSプロジェクトのファイルをJavaから直接操作できるライブラリを発見。日本語もいけるんでしょうか。
http://mpxj.sourceforge.net/

via kwout

木曜日, 6月 26, 2008

[Perl] 野良ppmの探し方

tcoolというサイトがあり、Seleniumのパッケージはありました。

月曜日, 6月 16, 2008

[Linux] unfuffle

unfuddleという無料のSVNリポジトリを初めて使ってみた。ただリポジトリを無料でインターネットに公開しただけじゃなく、UIとしてとても優れいていて使いやすそう。
http://unfuddle.com/

via kwout

普通のSVNなんだけど、以下コマンドラインでの使い方。
[f0054@divers-high ~]$ svn checkout http://tf0054.unfuddle.com/svn/tf0054_mm/
認証領域: <http://tf0054.unfuddle.com:80> Unfuddle Subversion Repository
'tf0054' のパスワード:
リビジョン 0 をチェックアウトしました。
[tf0054@divers-high ~]$ cd tf0054_mm/
[tf0054@divers-high tf0054_mm]$ ls -la
合計 24
drwxrwxr-x  3 tf0054 tf0054  4096  6月 16 01:50 .
drwxr-xr-x 28 tf0054 tf0054 16384  6月 16 01:50 ..
drwxrwxr-x  6 tf0054 tf0054  4096  6月 16 01:50 .svn
[tf0054@divers-high tf0054_mm]$ cp -pir ~/btmail/post_bgnote.pl ./
[tf0054@divers-high tf0054_mm]$ ls -la
合計 28
drwxrwxr-x  3 tf0054 tf0054  4096  6月 16 01:50 .
drwxr-xr-x 28 tf0054 tf0054 16384  6月 16 01:50 ..
drwxrwxr-x  6 tf0054 tf0054  4096  6月 16 01:50 .svn
-rwxr-xr-x  1 tf0054 tf0054  3237  6月 16 01:23 post_bgnote.pl
[tf0054@divers-high tf0054_mm]$ svn add post_bgnote.pl
A         post_bgnote.pl
[tf0054@divers-high tf0054_mm]$ svn commit -m 'First Add'
[tf0054@divers-high tf0054_mm]$ 

ちなみに、UTF8で入れるときちんと日本語のコメントも入りました。

土曜日, 6月 14, 2008

[Linux] 添付可能なメール送信"コマンド"

ファイル添付が可能なメール送信コマンド"email"(そのままですが)。
監視メールや集計結果メールなど、メール添付でメーラに結果がくればうれしいのに、でもそのためにPerlでプログラム書くのもなぁ、と思ったことは片手に収まらないハズ。
http://www.cleancode.org/projects/email

via kwout

電子署名とかいりませんが、本当にこういうのが「カユいところに」だと感じます。

木曜日, 6月 05, 2008

[Linux] PostgreSQL+LVM

LVMを使ってPostgreSQLのデータベースデータをバックアップするスクリプト。MySQLのがベースだそうですが、確かにそろそろ安定性から考えても実用に耐えうる状態になっていそうな(検証する価値がありそうな)気がします。
http://people.planetpostgresql.org/xzilla/index.php?/archives/344-guid.html

via kwout

月曜日, 5月 26, 2008

[Linux] Selenium GRID example

Selenium GRIDのexampleを動かしてみた。
D:\selenium-grid-1.0\examples\java>ant run-in-sequence

これでexamples\java\src\com\thoughtworks\selenium\grid\examples\java以下のファイルをいぢれば、やりたいテストができる、、のかな。

あと、、Proxyを通してテストをさせる(RCさんの上位にProxyを置く)にはどうするのだろう。setproxyタスク(?)でもうまく行かないし。。

<target ... >
<setproxy proxyhost="xxx.digipepper.com" proxyport="8080"/>

日曜日, 5月 25, 2008

[Linux] Selenium HTMLSuite

テスト自体はテストケースと呼ばれ、作ったいくつかのテストケースをまとめて実行させるため、それらのリンクを書いたやつのことをテストスイートというらしい。
その後者、スイートを自動生成したり、ブラウザを使い分けて実行したりすることができるJavaライブラリとしてのエクステンションがあったのでメモ。
clipped from www.enjoyxstudy.com

Selenium Remote Control(以降Selenium RC)におけるHTMLSuite(HTML形式で記述したテストスイート)の実行を、より手軽に、より便利にするためのライブラリです。

 blog it

[Linux] Selenium GRID

自動運転のピアノなごとく、ブラウザを操作して各種テストを行うSeluniumですが、複数のブラウザを同時に操作してテスト、するにはこのミドルでやるそうです。
 blog it
で、ちょっとやってみたとき、先に入れていたFirefox3(RC1)をうまく操作してくれなかった。。でIEを使うようにしたら無事動いた(と思う)。変更はbuild.xmlに以下。
D:\selenium-grid-1.0>diff build.xml.f build.xml
10c10
<   <property name="browser" value="*chrome" />
---
>   <property name="browser" value="*iehta" />
75c75
<   <property name="environment" value="*chrome"/>
---
>   <property name="environment" value="*iehta"/>

D:\selenium-grid-1.0>
昨今AJAXなサイトが増えてきており、、、JMeterでは少しつらくなってきた気がしています。無論がんばってシナリオを作ればよいのですが。

土曜日, 5月 24, 2008

[Flash] APE

Flashの物理エンジンというものがあるらしい。Flashコンテンツって自然界の動きをシミュレートしてみせることでかっこよくなるのだと思うので、その意味ではこんなのが大事なのだろうと思う。
clipped from www.cove.org
 blog it

月曜日, 5月 19, 2008

[linux] Paros

ParosというProxy型ウェブサイト脆弱性調査アプリ。多少日本語情報もあるので後で見てみたい。
http://www.parosproxy.org/index.shtml

via kwout

水曜日, 5月 14, 2008

[Life] wgetをproxy経由で

Windowsでwgetを使うとき、PROXY指定をしたかったら以下のように。
set http_proxy=squid.xxx.com:8080

意外にすぐわからなくなるのでメモ。

土曜日, 5月 10, 2008

[Life] DISQUS

ブログのコメント管理だけを切り出したサービス。コメントされたらメールがきて、それに返信したらスレッドに追記されるとか。。。
clipped from disqus.com
disqus_logo.png
 blog it
日本語コメントはきちんと見えることを確認!
が、(やはりといえばそうだが)返信は日本語が通りませんでした。。
プロジェクト管理で使っているMantisもそうなのですが、メールでコメントを返信できるととっても便利なので、、とても惜しい!です。

金曜日, 5月 02, 2008

[Life] ブログにソース

ブログにソースなどを張るとき、「HTMLのエンコードをしないと」と思いつつ、手でやるには面倒。。。そんなときにはこのページ(HTMLエンコードフォーム)。

水曜日, 4月 30, 2008

[Linux] bdbのダンプ

以外に忘れるのでメモベースで。
[tf0054@divers-high bird]$ db_dump -p tiedbfile
VERSION=3
format=print
type=hash
db_pagesize=4096
HEADER=END
/r/r/r.png
204,222
DATA=END
[tf0054@divers-high bird]$

月曜日, 4月 28, 2008

[PostgreSQL] PgQ続き(PerlでConsumer)

キューに入ったジョブを処理するプログラムを作りたいのだが、Pythonのフレームワークが提供されているのみでなかなか(Python以外で)書くことが難しい。何をどう呼んだら登録されるのか分からないし。。。
なので、大枠を例のままPythonを使って動かし、肝心の処理関数(通常はProcess_batch())だけをPerlで記述するためのTIPS。
#!/usr/bin/perl

use Data::Dumper;
use Sys::Syslog;

use Inline Python => <<'END_OF_PYTHON_CODE';
import sys, os, pgq, skytools
import syslog ,time

class zConsumer(pgq.Consumer):
def __init__(self, service_name, db_name):
self.procEvent = perl.procEvent;
pgq.Consumer.__init__(self, service_name, db_name, ["/tmp/var/mqueue/consumer.ini"])
def process_batch(self, src_db, batch_id, ev_list):
for ev in ev_list:
d = ev.data
self.log.debug ("event: %s | type: %s | extra1: %s" % (d, ev.type, ev.extra1))
if not self.procEvent(ev):
ev.tag_retry()
else:
ev.tag_done()

END_OF_PYTHON_CODE

my $objPgq = zConsumer->new("mqueue_consumer","src_db");

#print Dumper($objPgq);
$objPgq->start();

# イベント処理関数は、この関数を差し替えることでPerlで書けます
sub procEvent{
openlog(__FILE__, 'cons,pid', 'local4');
syslog('debug', 'this is Inline test');
closelog();

print Dumper(shift);
}

(Inline::Pythonのおかげで)上のプログラムでは各イベントを処理する部分だけ、procEvent()関数に切り出せていると思うので、これを書き換えればよい(=Perlで処理が書ける)です。
一部設定ファイルの指定は配列で渡さないとだめなのですが、Perlから渡すとなぜか上手くいかないので内部で宣言してしまっていますが、、、また調べます。

初めて使いますが、Inline::Pythonって便利ですね。これだあればアドオンモジュールをPythonで書かなくてはならない某商用アプリなんかも倒せそう。

日曜日, 4月 27, 2008

[PostgreSQL] PgQ続き(メンテナンス)

PgQでは、各キューそれぞれに3つのイベント格納用テーブルが用意してあり、それらを順繰りに使うことでバキューム対象となるデッドタプルが増えたテーブルをキュー処理に使わないようにし、ディスクIOを減らしている(らしい)。

tickerって5分に一度メンテナンスをしているが、上記のようなことをやっていたのですね。関数(PostgreSQLのPgQを仕込んだデータベースに格納された関数)が、下記が順に呼ばれています。
 ・maint_rotate_tables_step1(実際のローテートを行う)
 ・maint_rotate_tables_step2(その際にTXを付け替える)
 ・maint_tables_to_vacuum(バキューム対象テーブルをリストする)
ちなみに、ソース的には実際のバキューム処理はskytools-2.1.6/python/pgq/maint.pyに含まれています(あとTXってのはPgQ独自のトランザクションNo?のことだと思います)。

土曜日, 4月 26, 2008

[PostgreSQL] PgQ続き(リトライ他)

ジョブの戻し方おいて、リトライキューやフェイルキューにちゃんと入るかの実験、、をしていたらSkyTools(v2.1.6)にバグ発見(但しもうCVSでは修正されていました)。

こけさせるconsumer.pyは以下のようなやつで。

#!/usr/bin/python
import sys, os, pgq, skytools
import syslog

class Mailer(pgq.Consumer):
def sendWelcomeMail(self, params):
syslog.openlog("skycon")
syslog.syslog(params)
syslog.closelog()
return False

def process_batch(self, src_db, batch_id, ev_list):
for ev in ev_list:
d = ev.data
self.log.debug ("event: %s | type: %s | extra1: %s" % (d, ev.type, ev.extra1))
if not self.sendWelcomeMail(d):
ev.tag_retry()
else:
ev.tag_done()

if __name__ == '__main__':
script = Mailer("mailer_daemon","src_db",sys.argv[1:])
script.start()

これによりリトライキューに入ることを確認。

tf0054=# select * from pgq.retry_queue;
-[ RECORD 1 ]--+------------------------------
ev_retry_after | 2008-04-26 01:30:40.307409+09
ev_id | 15
ev_time | 2008-04-26 01:15:17.024847+09
ev_txid |
ev_owner | 1
ev_retry | 1
ev_type | welcome_email
ev_data | root@gmail.com
ev_extra1 |
ev_extra2 |
ev_extra3 |
ev_extra4 |

tf0054=#

ちなみに、consumerが稼動した最終時刻をみるためには以下。

tf0054=# select * from pgq.subscription;
-[ RECORD 1 ]-+------------------------------
sub_id | 1
sub_queue | 1
sub_consumer | 1
sub_last_tick | 2118
sub_active | 2008-04-26 06:38:03.550572+09
sub_batch |
sub_next_tick |

tf0054=#

というか日本語でも英語でも、Skytools全体がそうですが、特にconsumerのサンプルがまったくなくて困惑です(tag_retryなんてものクラス説明から見つけた)。

金曜日, 4月 25, 2008

[PostgreSQL] PgQ続き(設定ファイル)

それぞれpgqadm.py用と、consumer.py(キュー処理用の準備すべきプログラム)用の設定ファイルは以下のとおりでやってみます(昨日の続き)。

pgqadm.ini
[pgqadm]

job_name = ticker_test

db = dbname=tf0054 port=5432 host=127.0.0.1

# how often to run maintenance [minutes]
maint_delay_min = 5

# how often to check for activity [secs]
loop_delay = 0.1

logfile = /tmp/var/log/%(job_name)s.log
pidfile = /tmp/var/pid/%(job_name)s.pid

use_skylog = 0

consumer.ini
[mailer_daemon]
job_name = mailer_daemon
src_db = dbname=tf0054
pgq_queue_name = mailer
logfile = /tmp/var/log/%(job_name)s.log
pidfile = /tmp/var/pid/%(job_name)s.pid

木曜日, 4月 24, 2008

[PostgreSQL] PgQ

いまいち使い方が分からなかったPgQ(SkyToolsの一部であるジョブキューの仕組み)のお試しが出来たのでメモ.やることとしては,

  1. pgqadm.pyを使うためにPYTHONPATH環境変数をexport(skytools/lib/ython2.4/site-packages)
  2. 適用するデータベースを作る(ここでは"XXX"とする)
  3. pgplsqlがそのデータベースで使えるか確認(pg_languageカタログ/無いならcreatelang)
  4. share/skytools以下のsqlスクリプトを流す(txid.sql>pgq_ext.sql>pgq.sqlの順?)
  5. キューを"select * from pgq.create_queue(’mailer’)"で作成
  6. psqlで接続し"select * from pgq.queue"で確認
  7. tickerデーモンを起動する(例えば"../bin/pgqadm.py ./pgqadm.ini ticker -d")
  8. consumerデーモンをpythonで作る(※下にサンプルソースを掲示)
  9. consumerデーモンを起動する(例えば"../var/consumer.py consumer.ini -v")
  10. キューに入れてみる(入れるものをイベントと言う.例えば"select pgq.insert_event('mailer','welcome_email','tf0054@gmail.com')")

と言った感じ.こちらのサイトを参考にしたが,トリガを作ってイベント登録をさせる仕組みが面倒だったので直接インサートして実験.
また,サンプルのconsumerデーモンのPythonソースが一部実装されてないので,以下な感じで補完することが必要。
#!/usr/bin/python
import sys, os, pgq, skytools
import syslog

class Mailer(pgq.Consumer):
def sendWelcomeMail(self, params):
syslog.openlog("skycon")
syslog.syslog(params)
syslog.closelog()
return True

def process_batch(self, src_db, batch_id, ev_list):
for ev in ev_list:
d = ev.data
self.log.debug ("event : %s | type : %s | inserted by : %s" % (d, ev.type, ev.extra1))
if not self.sendWelcomeMail(d):
sys.exit(1)
ev.tag_done()

if __name__ == '__main__':
script = Mailer("mailer_daemon","src_db",sys.argv[1:])
script.start()

これを以下のとおり実行して、
./consumer.py ../etc/consumer.ini &

syslogにデータでるところまで確認できました.また,使える関数などはこちらで見られます.あれ?でも,,,
  • tickerは何をしてくれるんだっけ?
  • pgqadmのinstallってしてなかったけどいいの?

土曜日, 4月 12, 2008

[Linux] tinc

VPNを張るためのデーモン。IPSECほど本格的でなくてもよい用途には適していると思います。
clipped from www.tinc-vpn.org
tinc
 blog it

木曜日, 4月 10, 2008

[Linux] unexpected zero page

レンタルサーバにZABBIXを入れてリソースを検証こめて見ているのですが、障害によるリブートがあったらしく、ZABBIX_SERVERが起動しなくなった。ログを見ていると、
22439:20080410:024033 Query::select min(clock) from history_uint where itemid=18450
22439:20080410:024033 Query failed:PGRES_FATAL_ERROR:ERROR: index "history_uint_1" contains unexpected zero page at block 13758
HINT: Please REINDEX it.

PosrgreSQLを使っているので以下コマンドを実行して解消。
zabbix=> reindex index history_uint_1;
REINDEX
zabbix=> \q

火曜日, 4月 08, 2008

[Linux] amebloもですね

アメブロでもリファラでの画像閲覧禁止がなされているんですね。
確かに直リンクなどは論外ですが、しかしgoogleリーダなどから写真が見られないのはちょっと。。ということでY!同様にリファラプロキシで対応。
Y!とちがって普通に組むとgzip圧縮応答されたり、HOSTヘッダによるリダイレクトが入ったりと、いくつかはまりました。。

土曜日, 4月 05, 2008

[Linux] ebb

libevを使った高速httpd。Rubyな香りがしていますが、これ単体で使うことができそうです。
clipped from ebb.rubyforge.org
Benchmark
 blog it

nginxやlighttpdと比較してどうなのでしょう。

金曜日, 4月 04, 2008

[Linux] libev

memcachedはすこぶるリソース消費が少ないことを体感していた矢先、その中核であるlibeventの対抗馬libevを見つけた。
よりメモリ消費が少ない
より効率的なイベントループ
libeventエミュレートモードあり

と書かれており、確かにベンチマーク資料を見てもよさげに見えますので、何かの折に。