scala

2008-11-09

jruby と ruby での DB アクセスの速度 (その3)

ATOKダイレクトプラグインで郵便番号検索

自宅には、Windows マシンが無いので、休日に会社マシンで、ATOK ダイレクトプラグインの環境を設定し、すこし遊んでみた。

web 上のいくつかのサンプルコードで、作り方を勉強した後、
昨日作った ruby での郵便番号番号検索を、ATOK プラグイン化してみた。
郵便番号の一部 or 住所の一部で検索できるようにしてある。
作ってみて思ったのは、2点。
1. ATOK の選択候補画面のカスタマイズもユーザー側でできるようにして欲しいということ。
   候補画面の GUI も ruby で作りたいものだ。
2. Debug 環境は、もう少し工夫したものが作れそうな気がする。
    Netbeans 上でのデバッガをつかえような、実行用メインメソッドをつくれば済む?

なお、sqlite3 の DB は、 firefox のプラグインの SQLite Manager を使うと内容確認などには便利。

$ cat zip-search.rb
#! /usr/bin/ruby -Ku

$KCODE = 'u'

require 'timeout'
require 'rubygems'
require 'active_record'
require 'nkf'

module Atok_plugin

  class Zip < ActiveRecord::Base
    def to_s
      return  "#{col1}|#{col2}|#{col3}|#{col4.toutf8}|#{col5.toutf8}|#{col6.toutf8}|#{col7.toutf8}|#{col8.toutf8}|#{col9.toutf8}|#{col10}|#{col11}|#{col12}|#{col13}|#{col14}|#{col15}"
    end
  end

  def run_process( a_request_data )
    ActiveRecord::Base.establish_connection(
                                            :adapter  => "sqlite3",
                                            :database => "zips.db",
                                            :timeout  => 5000
                                            )
    # ログをファイルに出す
    # ActiveRecord::Base.logger = Logger.new("debug.log")

    res = []
    timeout(20) do
      key = "%" + a_request_data['composition_string'] + "%"
      res = Zip.find(:all, :conditions => ["col3 like ? or col7 like ? or col8 like ? or col9 like ?", key, key, key, key])
    end
    ans = []
    res.each do |r|
      ans << {'hyoki' => r.col3 + "|" + r.col7 + r.col8 + r.col9, 'comment' => r.to_s}
    end
    {'candidate' => ans}

  rescue Exception => e
    {'candidate' => [{'hyoki' => 'エラーが発生しました', 'comment' => e.to_s}]}
  end

end

ローカルマシンの DB 管理するよりは、memcached でデータを共有したほうが良い気がする。
memcached で、社員名簿 (名前、内線番号、所属部署) などを保持して、それを ATOK + ruby で検索したり、データ内容の保守ができるようにするぐらいが向いているかな。

ともかくここ2日の作業で、10 万件を超える郵便番号の検索が ATOK + ruby で十分可能なことが分かった。
XBRLデータから科目ID, 科目表記名、期間毎の値 をDBに保持して それを検索するようなことは、問題なく実現できそうだとの感触を得られた。

| | コメント (1) | トラックバック (0)

jruby と ruby での DB アクセスの速度 (その2)

scala でも sqlite3 に入れた郵便番号を検索させてみた。

$ cat  search.scala
/
// $ calac search.scala
// Then
// $ scala -classpath .:sqlitejdbc-v053.jar sqlitetest
//  or
// $ java -cp .:sqlitejdbc-v053.jar:/opt/local/share/java/scala-library.jar sqlitetest
//

import java.sql._

object sqlitetest extends Application {

  var conn: Connection = null
  var stat: Statement = null
  var rs: ResultSet = null

  try {

    Class.forName("org.sqlite.JDBC")

    conn = DriverManager.getConnection("jdbc:sqlite:zips.db")
    stat = conn.createStatement 
    rs = stat.executeQuery("select * from zips where col3 like '100000%';")

    while (rs.next()) {
      println(
    rs.getString("col1") + "|" +
    rs.getString("col2") + "|" +
    rs.getString("col3") + "|" +
    rs.getString("col4") + "|" +
    rs.getString("col5") + "|" +
    rs.getString("col6") + "|" +
    rs.getString("col7") + "|" +
    rs.getString("col8") + "|" +
    rs.getString("col9") + "|" +
    rs.getString("col10") + "|" +
    rs.getString("col11") + "|" +
    rs.getString("col12") + "|" +
    rs.getString("col13") + "|" +
    rs.getString("col14"))
    }
  } catch {
    case e => e.printStackTrace
  } finally {
    if (rs == null) rs.close
    if (stat == null) stat.close
    if (conn == null) conn.close
  }
}

$ time scala -classpath .:sqlitejdbc-v053.jar sqlitetest
13101|100  |1000000|トウキョウト|チヨダク|イカニケイサイガナイバアイ|東京都|千代田区|以下に掲載がない場合|0|0|0|0|0
13101|100  |1000004|トウキョウト|チヨダク|オオテマチ|東京都|千代田区|大手町|0|0|1|0|0
13101|100  |1000002|トウキョウト|チヨダク|コウキョガイエン|東京都|千代田区|皇居外苑|0|0|0|0|0
13101|100  |1000001|トウキョウト|チヨダク|チヨダ|東京都|千代田区|千代田|0|0|0|0|0
13101|100  |1000003|トウキョウト|チヨダク|ヒトツバシ(1チョウメ)|東京都|千代田区|一ツ橋(1丁目)|1|0|1|0|0
13101|100  |1000005|トウキョウト|チヨダク|マルノウチ(ツギノビルヲノゾク)|東京都|千代田区|丸の内(次のビルを除く)|0|0|1|0|0
13101|100  |1000006|トウキョウト|チヨダク|ユウラクチョウ|東京都|千代田区|有楽町|0|0|1|0|0

real    0m0.658s
user    0m0.397s
sys    0m0.176s

エラー処理の書き方がだめだが、速度はまあまだ。
jruby が遅かったのは、ソースのコンパイル時間が発生する為と思われる。
jrubyc でコンパイルすれば、速くなるかな?

$ jrubyc jserach.rb

$ java -cp .:$JRUBY_HOME/lib/jruby.jar jsearch
Exception in thread "main" jsearch.rb:4:in `require': no such file to load -- pp (LoadError)
    from jsearch.rb:4
    ...internal jruby stack elided...
    from Kernel.require(jsearch.rb:4)
    from (unknown).(unknown)(:1)

うーん、jrubyc で compile した class の実行法がうまくいかないなぁ...

| | コメント (0) | トラックバック (1)

2008-03-25

DouKaku? の ポーカーの役判定

http://ja.doukaku.org/121/
>> ポーカーの役判定
の いろいろな言語での解答例をいろいろ読んでみている。

Scala, Haskell はなかなか短い。
prolog は思ったより長いし、なぜか理解しにくいなぁ。
java, 長過ぎる...

| | コメント (0) | トラックバック (0)

2008-03-21

scala で xml を扱う

scala で XML は簡単に扱える。(ruby 並み)

doukaku.org にあった net から html を取得して、特定の値を取り出す例だ。

$ cat Rss.scala
// See http://ja.doukaku.org/19/nested/
//     http://www.scala-lang.org/docu/files/api/scala/xml/parsing/ConstructingParser.html

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

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

    // val url = "http://feeds.feedburner.com/Scala"
    val url = "http://ja.doukaku.org/feeds/comments/"

    val data = Source.fromURL(url)
    val elem = ConstructingParser.fromSource(data,true).document().docElem

    println((elem\"channel"\"lastBuildDate").text)

    // import scala.xml.PrettyPrinter
    // Console.println( new PrettyPrinter(80 /*width*/, 2 /*indent*/).format(elem) )
  }
}

コンパイルして、実行しよう。
$ scalac Rss.scala
$ scala -cp . Rss

Thu, 20 Mar 2008 09:20:47 -0000

scala での xml の処理の方法の入門は次のページが面白い。
- http://burak.emir.googlepages.com/scalaxbook.docbk.html
> > scala.xml

val company  = <a href="http://acme.org">ACME</a>
とか、
val embBook =
    <phonebook>
      <descr>
        This is the <b>phonebook</b> of the
        {company} corporation.
      </descr>
    </phonebook>;
のように、変数に直接 XML を記述したり、XML 中に変数を埋め込んだりできるのだ。
XML を扱う上ではとても便利。(java だとそうはいかず、面倒だ)

記事中のソースコードは subversionで取得できる。
http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk/docs/examples/xml/phonebook/

閲覧するだけなら
https://lampsvn.epfl.ch/trac/scala/browser/scala/trunk/docs/examples/xml/phonebook

xfy/xvcd で scala スクリプトをそのままかけるようにすることと、 java の代わりに scala で logic を記述することの両方をサポートすると面白そうだ。

| | コメント (0) | トラックバック (0)

2008-03-20

maven2 で scala を試す。

maven2 で scala を試してみた。

$ mvn -v
mvn -v
Maven version: 2.0.8
Java version: 1.5.0_13
OS name: "mac os x" version: "10.4.11" arch: "ppc" Family: "unix"

$ mvn -U archetype:generate
  ... 省略 ...
Choose archetype:
1: internal -> appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)
... 省略 ...
Choose a number:  (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) 15: : 2

うーん、この一覧中には scala は無かった. orz...

そこで後は、次の記事に従って試した。
- http://scala-blogs.org/2008/01/maven-for-scala.html
> > Scala Blog: maven for scala

$ mvn org.apache.maven.plugins:maven-archetype-plugin:1.0-alpha-7:create -DarchetypeGroupId=org.scala-tools.archetypes -DarchetypeArtifactId=scala-archetype-simple -DarchetypeVersion=1.1 -DremoteRepositories=http://scala-tools.org/repo-releases -DgroupId=com.katoy.sample -DartifactId=my-app

$ cd my-app

pom.xml 中で、scala のバージョンが
  <properties>
    <scala.version>2.6.1</scala.version>
  </properties>
となっているので、2.7.0 に編集した。
(http://scala-tools.org/repo-releases/org/scala-lang/scala-library/
  辺りをみれば、どんな version が公開されているかが判る)

$ mvn test
上の記事にもあるけど、generate される test コードではエラーが発生する。
これは 上の blog 記事にもあるけど ちょちょっと直せばよいだけ。

ここまでで、つぎのようにファイルが構成される。
$ tree
.
|-- pom.xml
|-- src
|   |-- main
|   |   `-- scala
|   |       `-- com
|   |           `-- katoy
|   |               `-- sample
|   |                   `-- App.scala
|   `-- test
|       `-- scala
|           `-- com
|               `-- katoy
|                   `-- sample
|                       `-- AppTest.scala
`-- target
    |-- classes
    |   `-- com
    |       `-- katoy
    |           `-- sample
    |               |-- App$.class
    |               `-- App.class
    |-- classes.timestamp
    |-- surefire-reports
    |   |-- TEST-com.katoy.sample.AppTest.xml
    |   `-- com.katoy.sample.AppTest.txt
    |-- test-classes
    |   `-- com
    |       `-- katoy
    |           `-- sample
    |               |-- AppTest$.class
    |               `-- AppTest.class
    `-- test-classes.timestamp

実際に run させてみよう。
$ scala -cp target/classes com.katoy.sample.App
Hello World!

java で走らせるには scala-library.jar を classpath に含めてやればよい。
$ java -cp /opt/local/share/java/scala-library.jar:target/classes com.katoy.sample/App
Hello World!

$ mvn package

target/my-app-1.0.SHAPSHOT.jar が生成される。

$ java -cp /opt/local/share/java/scala-library.jar:target/my-app-1.0-SNAPSHOT.jar com.katoy.sample/App
Hello World!

最後は clean しておこう。
$ mvn clean

xfy/xvcd において、java でロジックを記述するかわりに scala もつかうことも出来そうだ。

| | コメント (0) | トラックバック (0)