2013年3月22日金曜日

GAE/J + JDO で Single Property Index を作らせない

表題のとおりですがようやくたどり着いたのでメモ。

サイト自体にも書いていますが、#f1yosou Google App Engine/Java (以下 GAE/J)を使っています。もともと3年前(もう3年になりますか・・・)にはじめたときには結構余裕だったのですが、Googleさんの緩やかな締め付けwで無料での利用部分がどんどん制限されてきて、最初のころにはタコなコードを書いていても余裕があったのですが、最近はかなり厳しくなってきています。これまでもそれなりに使用量を抑制しつつなんとかごまかしてきました。

そんな最近の #f1yosou サイトのもっとも厳しい項目は、Datastore Write Operations の項目です。これは文字通り Entity を Datastore に書き込むと消費するやつですね。これが特に #f1yosou タグのついたツイートを解析して結果を書き込む処理を経るとかなり消費されます。処理としては
  • 該当するツイートの保存
  • 同一の予想をしたツイートのカウントを行い、その結果を保存
ということをしていますが、どうも後者の処理がかなりの書き込みを生じているようです。そもそもこの Datastore Write とは Entity を1つ書き込むと1回なのか?というところから調べ始めたところ、以下の記事がよくまとまっておりました。
EntityのPropetryの構成よって、Datastore writeの数は変わる!
なるほど。そもそもプロパティの数によって増えるのもあるんですがそれは実際に値をしまってるので仕方ないとして、各プロパティについて勝手に自動的に作成される Index の書き込みのほうが問題ですね。そもそも使ってないのに昇順・降順で2つ作られてるみたいですし。これを削減できればだいぶ効きそうです。ただし
Single Property Indexを作らないとComposite Indexも作成されない?
という考慮点もあるみたいなのでなんでもかんでも削れるわけではないようです。

と、ここまできて JDO ではどうやって指定するんだろう・・・と思って調べてもなかなかでてきません。いろいろググっていたらようやく Entity#setUnindexedProperty() なるものがでてきました。しかしこれも Low Level API。。。

まあそれでもいいか、と思ってやり方を探っていたらとうとう発見しました。まんまの質問がありましたw なぜこれに最初に行き当たらなかったのか不思議なぐらいそのままです。要するに
@Extension(vendorName = "datanucleus", key = "gae.unindexed", value="true")
を索引がいらないプロパティにつけるだけです。あら簡単。

早速実験してみます。1回処理すると以下のようになる Entity を用意しました。
 このクラス定義のところにある correct というプロパティに Index を作らないようにします。
 @Persistent
 @Extension(vendorName = "datanucleus", key = "gae.unindexed", value="true")
 private Boolean correct;
とすると、
のように2減りました。この2というのが昇順と降順で1つずつの結果のようです。
#上では赤丸がついている Entity にのみ処理をしました。

これで削減できるかな?

2013年3月18日月曜日

Eclipse + Maven その2

続きです。これだけでも十分便利なんですが、よくできてんなと思ったところをもう少し。今回想定しているのは前回作ったプロジェクトで Selenium を使ったコードを書いて隠蔽し、それを別のプロジェクトから利用するというシナリオです。

まず sample1 の App クラスを変更しておきます(別に main のままでもできますが、雰囲気を出すために)。そして後述する実験のために一度 sample1 を install しておきます。sample1 の pom.xml を右クリックして、Run As -> Maven install... を実行します。
 sample1 と同じように sample2 プロジェクトも作ります。
で、pom.xml を開き、dependency のところで sample1 を追加します。
すると
のようになります。アイコンでわかるとおりプロジェクト参照になってます。なので普通に sample1 のクラスが使えるので
とやって実行しただけでブラウザが上がってきます。

これだけでも十分便利なんですが、よくできてんなと思ったのはこの先です。さきほどプロジェクト参照になってると書きましたので、sample1 の App のほうを

のように変更して sample2 の Main を実行すると
と Yahoo! が開きます。ここで sample1 を閉じます。
すると先ほどプロジェクト参照になっていたものが最初にインストールしたほうに自動的に変更されます。
なので実行すればちゃんと動作しますが、開くのは Google のほうです。つまり、インストールされていればその依存を書くだけで使えますが、プロジェクトがあればそちらのコード変更を即座に反映した開発が可能ということです。これは便利ですね。

2013年3月16日土曜日

Eclipse + Maven その1

ひょんなことから Selenium を使う機会がありまして。それ自体はいいんですが前提のライブラリが多いこと多いこと・・・。これをマネージするのは正直つらそう。そう思いましてせっかくなので Maven を使ってみました。これは便利ですね。なので備忘録をかねて少々ご紹介。

まずは m2e を入れておきます。するとプロジェクトを作成するときに Maven Project が選べるようになります。
  先へ進んで最後に Group Id と Artifact ID を入れると


こんな感じにプロジェクトが作成されます。
左上に「M」がついてるので Maven 用に構成されたプロジェクトであることがわかります。pom.xml も作成されているので開くとエディターが開きます。
今回は Selenium を使いたいので依存関係を定義します。Dependencies のタブを開いて Add をクリックします。ダイアログが開くので、フィルターのところに selenium-java と入力して selenium-java を選んで

追加します。すると

このように自動的に classpath にも追加されます。こうなれば

のようにコードを書いて実行すると
 と動くわけです。

2013年3月10日日曜日

CentOS で 宅内 DNS の構築

開発機のアドレスが正しくアサインされてなかったことに気づいてあわててルーターの設定を直していたのですが、そのときにいつも http://192.168.0.1 と打ってまして、これなんとかならないのかなぁと思っておりました。よく使うマシンとかは hosts に書いてるんですが、家には何台かマシンがあり、全部のファイルを管理するのは嫌なので。そこでせっかく Linux マシンがあることだし、宅内用に DNS を構築してみることにしました。

まずはいつものように
# yum install bind

(snip)

Installed:
  bind.x86_64 32:9.8.2-0.17.rc1.el6.3
でインストールします。設定ファイルは /etc/named* と /var/named/* に配置されます。まず /etc/named.conf の options に以下のエントリを追加してローカルネットにのみ使用されるようにします。
        allow-query{
                127.0.0.1;
                192.168.0.0/24;
        };
        allow-recursion{
                127.0.0.1;
                192.168.0.0/24;
        };
        allow-transfer{
                127.0.0.1;
                192.168.0.0/24;
        };
次にLAN内以外の名前解決のため、ほかの(もともと使っていた)DNSサーバーを指定します。うちの場合はルーターを指定すればよいので以下のようになります。
        forwarders {
                192.168.0.1;
        };
さて解決したいアドレス群たちは別ファイルにします。named.conf で directory のところに指定されたディレクトリ、恐らく /var/named になっていると思いますが、そこにファイルを作成することになります。named.conf にはそのエントリだけです。
zone "mydomain.net" {
        type master;
        file "mydomain.net";
};

zone "0.168.192.in-addr.arpa" {
        type master;
        file "0.168.192.in-addr.arpa";
};
です。もちろん mydomain.net はご自分のドメインに書き換えてくださいね。

さてそれぞれのファイル自身の書き方が難しいです。named やら named.conf やらの man を見たんですが見つかりませんでした。このへんを参考にさせていただいて書いてみました。まずは正引き、つまり名前をIPアドレスに変換するほうです。
$TTL 1D
@       IN SOA  server.mydomain.net. root.server.mydomain.net. (
                                        2013030901      ; serial
                                        1D      ; refresh
                                        1H      ; retry
                                        1W      ; expire
                                        3H )    ; minimum
        IN NS   server.mydomain.net.
        IN MX 10        server.mydomain.net.
router  IN A    192.168.0.1
server  IN A    192.168.0.2

なにやら呪文のようですが・・・。アドレスの最後の . が結構肝みたいです。このファイル自体が "mydomain.net" 用というのを named.conf で指定したので、省略が利用できます。たとえば @ はそれ自身、つまり mydomain.net そのものの代わりです。また、 . で終わらないもの(上では router とか)は後ろに .mydomain.net がつくと解釈されます。なので、router の行では 「router.mydomain.net を 192.168.0.1 とする」という定義になります。

今度は逆引き、つまりIPアドレスを名前に変換するほうです。記法は基本一緒です。
$TTL 1D
@       IN SOA  server.mydomain.net. root.server.mydomain.net. (
                                        2013030901      ; serial
                                        1D      ; refresh
                                        1H      ; retry
                                        1W      ; expire
                                        3H )    ; minimum
        IN NS   server.mydomain.net.
        IN PTR  mydomain.net.
        IN A    255.255.255.0

1       IN PTR  router.mydomain.net.
2       IN PTR  server.mydomain.net.

ここでも同じです。さきほど 0.168.192.in-addr.arpa 用に定義したファイルなので、1 とかは 1.0.168.192.in-addr.arpa を定義したことになります。

これらのファイルが記述できたら、ツールで確認ができます。
# named-checkzone mydomain.net /var/named/mydomain.net 
zone mydomain.net/IN: loaded serial 2013030901
OK
# named-checkzone 0.168.192.in-addr.arpa 0.168.192.in-addr.arpa
zone 0.168.192.in-addr.arpa/IN: loaded serial 2013030901
OK
よさそうですね。いざ起動します。
# service named start
一応 /var/log/message を確認して大丈夫なことを確認して・・ってあれれ?
Mar  9 23:25:37 named[11531]: zone 0.168.192.in-addr.arpa/IN: loading from master file 0.168.192.in-addr.arpa failed: permission denied
Mar  9 23:25:37 named[11531]: zone 0.168.192.in-addr.arpa/IN: not loaded due to errors.
なるほど、ほかのファイルたちは group が named になってるのに私は root のままにしてました。
# chgrp named mydomain.net 
# chgrp named 0.168.192.in-addr.arpa 
# service named restart
今度は無事起動したようです。/etc/resolv.conf のエントリを /etc/sysconfig/network-scripts 等から変更し、ネットワークの再起動をします。確認します。
# nslookup router
Server:  127.0.0.1
Address: 127.0.0.1#53

Name: router.mydomain.net
Address: 192.168.0.1

# nslookup 192.168.0.1
Server:  127.0.0.1
Address: 127.0.0.1#53

1.0.168.192.in-addr.arpa name = router.mydomain.net.

# nslookup www.google.com
Server:  127.0.0.1
Address: 127.0.0.1#53

Non-authoritative answer:
Name: www.google.com
Address: 173.194.38.81
Name: www.google.com
Address: 173.194.38.82
Name: www.google.com
Address: 173.194.38.83
Name: www.google.com
Address: 173.194.38.84
Name: www.google.com
Address: 173.194.38.80

内部のアドレス、外部のアドレスとも問題なく解決されました。あとはこのサーバーをDNSサーバーとしてクライアントに登録するだけで利用できます。

実際に使ってみたところだめでした。 orz
原因の1つめは named.conf をよーく見ると
listen-on port 53 { 127.0.0.1; };

とありました。つまりそのサーバーだけでしか使えなくなっています。 上のテストはサーバー上だったので使えていたのですね。 まずはこれを修正します。 そうしたら一応使えてるっぽいんですが、なぜか1度目は失敗します。
C:\>nslookup www.formula1.com
サーバー:  server.mydomain.net
Address:  192.168.0.2

DNS request timed out.
    timeout was 2 seconds.
DNS request timed out.
    timeout was 2 seconds.
*** server.mydomain.net への要求がタイムアウトしました

C:\>nslookup www.formula1.com
サーバー:  server.mydomain.net
Address:  192.168.0.2

権限のない回答:
名前:    pc-b.bitgravity.com
Address:  64.185.181.238
Aliases:  www.formula1.com
          f1tata.pc.cdn.bitgravity.com
また /var/log/messages に戻ると、大量のエラーが。
Mar 10 00:14:14 named[13184]: validating @0x7fe418008ea0: . NS: got insecure response; parent indicates it should be secure
どうもルーターが dnssec に対応してないようですね。どうせLAN内だから別にいいか。(本当はどうかわからないですが。)/etc/named.conf の dnssec-validation を no に変えたところ無事動きました。

ネットワークの設定はいろいろ大変ですね。ここまでやってようやく http://router でルーターの管理画面に入れたわけですが、そこまでの価値があったのかどうかw まあ自己満足でOKとします。

2013年3月9日土曜日

外でスカパーが見たい(3)

えー、続報ですw

宿泊を予約してたんですが、子供たち用に夕食に「唐揚げ」を追加してくださいとお願いしていたところ、唐揚げとは鶏でしょうかというメールが来ましたw サイトで確認したところ確かにほかの唐揚げもありました。失礼しました。

その返事ついでに「ところでインターネット接続のサービスはありますか?」と問い合わせたところ「無線LANがございます」との返事が!Last one mile もつながりそうです。願わくは 2Mbps ぐらい出てくれるとうれしいですね。

これにて宿泊先からインディの開幕戦を見ることができそうです。最後に宿でAM1時に起きれるかという難問が残ってますけどw

2013年3月6日水曜日

外でスカパーが見たい(2)

続きです。おととい力尽きた時点では
  • ロケーションフリーを起動できた
  • 室内でちゃんと映像が見れることが確認できた
  • 外からは見れないが恐らくルーターが二重になっているせい
という状況でした。 それを解決すべく再度挑戦です。

まずはNTTのルーターの説明書を引っ張り出してきました。なぜか?管理画面に入る方法を思い出すためですw 説明書読んでいたら無事思い出して管理画面に入れました。たしかにこっちのルーターが一番外ですね。さてこのルーターをルーター機能を止めてただのモデムとして使うことができるのか・・・と思っていたら「PPPoE ブリッジ」なる機能を発見。ほほうこれはいけそうですね。そもそもこの機能は最初からオンになっていました。

内側のルーターの管理画面に入り、接続の方法をこれまでの「ローカルルーター」「DHCP」から「PPPoE」に変更します。そして接続をすると

WAN側IPアドレス 223.###.###.###

おおお、プライベートアドレスではなくなりましたね!

ロケーションフリーの管理画面に戻り、NetAV テストというメニューに進むと

「成功」

やりました~。この後 iPhone のテザリングでつないでみましたが、ちゃんと映像を見ることができました。めでたしめでたし。





・・・いまさらですが実は宿泊先にはインターネット接続サービスがないんじゃないか疑惑がw 続報を待て!(待たなくていいですw)

2013年3月4日月曜日

外でスカパーが見たい(1)

突然ですが、さる用事のために3月24日に外泊することとなりました。それ自体は別にいいんですが、問題が起こりました。この日は佐藤琢磨選手が参戦しているインディーカーシリーズの開幕戦の日じゃありませんか!去年もいろいろ興奮させてもらいましたが、今年もテストでトップタイムをたたき出すなど既に興奮気味なのです。なのにその開幕戦がライブで見れないとは!もちろん外泊のほうを調整できれば一番なのですが、来客ですし子供たちの予定も考えるとこの日しかないので・・・。うーむ。

こうなったらここはITで解決しましょう! しかし今回みたいなケースのために何かを買うのもなんなので、ここは戸棚に眠っていたロケーションフリー君を引っ張り出してきました。この製品はもはや伝説的ですよね。捨てないでおいてよかった。

早速接続してみます。無事起動しました。問題はソフトのほうですが、当時はまだ Windows 7 、しかも 64bit などなかった時代なので動かない危険性もありましたが、こちらも無事インストール完了しました。いざ起動!すると「既にほかのコンピューターで登録されています」という表示が。そうか、既に処分したパソコンで使ってたもの、と思ってヘルプを見ると管理画面から削除できるとのこと。よーし、いざログイン・・・パスワードなんて覚えてないです。 orz

困っていろいろ探っていたら、リセットボタンを押せば工場出荷時の状態に戻るとのこと。すばらしい。早速ペン先でリセットして再挑戦。そしてキター!
砂嵐w

もちろんアナログ時代の製品なので今はアンテナつないだとしても映らないわけです。ビデオ入力だけが使えればいいので問題はないですが。無事見れることが確認できました。

次の問題は、外から見れるのか、です。同一ネットワーク内では直接接続できてても外からだとルーターをはさむので必ずしもつなげるとは限らないわけです。それをどう確認するか?昔は emobile やら WiMAX やら持っていましたが、今は持ってないので確認が難しいですね。・・・と思ったら、iPhone があるじゃないですか!テザリングですよ奥さん!(古

このブログ読まれてる方はご存知かも知れませんが、私のは iPhone 4S の SIM フリー版で、SIM には楽天ブロードバンドLTEのものをさしています。なのでいけるはず。モバイルネットワークの設定にインターネット共有という項目があってそこに APN やら何やらを入力します。1つ戻って「インターネット共有」のところで「オン」にすると、パソコンから見えるようになりました。接続すると

来たぜぇ~w

これでパソコンは室内にあるけどネットワーク的には外になりました。いざ接続テスト!・・・だめでした。 orz

当然ポート開けてないからだろ、というのは当然の意見ですよね。はいそうでしょう。ってポート何番だろう。そう思って管理画面に行くと、便利なものがありました。簡単設定なる項目です。なんていい製品なんだ。ここから設定すると勝手にDDNSサービスにも登録してくれて、UPnP なる規格によってルーターにポートを開けてその機器に転送してくれるように設定してくれるんですね(いまさら知ったw)。すばらしいなぁ。接続できたなぁ・・・

いやできてませんでしたw

原因のところに「二重にルーターをはさんでいませんか?」「グローバルIPは割り当てられていますか?」とかいろいろ理由が書いてありました。そんなの当然なんだけどなぁ。ほら、ルーターの設定画面には・・・

WAN側状態

IPアドレス/ネットマスク 192.168.1.2/24

!?はさんでる!ww

引っ越したときにそんな設定にしてたの忘れてました。1つは自分で買ったやつで、そのルーターからフレッツのルーターにつないでたんでした。なんでそうしたんだったかな?ルーター機能がオフにできないとかだっけな?ちょっと記憶が定かではないですが・・・。

というわけで明日以降フレッツのルーターの説明書引っ張り出して再挑戦します。なんとしても見てやる!