ドコモの中の人が「準拠」について勉強しているらしい。

はたと思って軽くgrepかけてみたら、こんなログがあった。

dish-sg.nttdocomo.co.jp - - [29/Nov/2007:21:13:46 +0900] "GET /000569.html HTTP/1.1" 200 23806 "http://www.google.com/search?sourceid=navclient&hl=ja &ie=UTF-8&q=%e6%ba%96%e6%8b%a0" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)"
勉強する方向性を間違ってますよ。

っていうか、「準拠」でググるとこの記事が3番目に来るという状況についてはなんてコメントしたらいいのかよくわからない。

しかしひとつだけ言える。RFCがどうの準拠がどうの、なんて話は実はどうでもよくて、 筆者がドコモやauに問いたいのはただひとつ 「いま現実に起きているこの混乱状況をどう収拾してくれる気ですか?」ということだ。

see also:

RFCの訳は「ご意見お待ちしております」では実はない。

RFCは「規定」である。「たたき台」ではない。 ところが、「Request For Comment = ご意見お待ちしております」という中学生でもできる直訳が一人歩きすることがよくある。

このような日本語訳は、少なくとも、本書いたり業界紙上で海外のプログラマーとの英語での対談を記事に書いたりするほどのポジションにいる人が、その歴史的経緯も添えずにただただ直訳して公開してしまうべき技術用語ではない。

と、ここで早速あやまっておきたい。ごめんなさい少し言い過ぎました。大筋にはまったく同意なのですよ。 (それにRFC原理主義よばわりされるのも本意じゃないしね。)

RFCってなに? (JPNICのサイトより)

RFCは"Request for Comments"の略で敢えて訳を付けるのならば『求むコメント』とでもなる用語である。 RFCに初めて触れた方の多くの方はまず『どうしてRFCが"RFC"と呼ばれているのか?』と、現在のRFCの位置づけと名前が持つ意味のギャップに悩むに違いない。 この悩みがRFCを理解する上で最初の関門であることは確かで、かつ、解消するまでに長い時間がかかる(かもしれない)ものなのだ。なぜなら、本当に正確な理解をするためにはRFCの歴史にまで踏み込まなければならない、からだ。

ということで、その言葉の本当の位置づけとはほど遠い翻訳がおもいっきり一人歩きしてしまいやすいのがこのテの技術用語のやっかいなところである。 自浄作用がまったく機能しないばかりか「国際的な話だから対応できない」というボケをかましてくる企業が相手の場合はなおさらのこと、このようなほとんど誤訳に近い単語を突破口(と勘違いして)に詭弁を講じてくる可能性は高いのだ。

see also:

ドコモもauもいいかげんにメールアドレス設定の仕様を直せ。の続きと補足

2007年5月某日。筆者の知人が関わっているWebサイトのサポート窓口宛に、次のような問い合わせが舞い込んだ。

注文後の確認のメールが届きません。私のアドレスは hogehoge...@xx.dion.ne.jp です。
もちろんhogehogeとかxxの部分は筆者による伏字である。注目すべきは赤字の部分。 携帯キャリアのドメインでもないのにこの連続ドット&@直前ドットのコンボは何事?!

そこから4ヵ月後を経て2007年9月21日。KDDIは次のようなリリースを出した。

KDDI、新ポータルサイト「au one」とISP「au one net」を9月27日開始 (broad band watch 2007/9/21)
KDDIと沖縄セルラーは、PCおよび携帯電話向けポータルサイトを一体化した「au one」を9月27日に開始する。合わせて、インターネット接続サービスのブランド名も「DION」から「au one net」へと正式に改称される。
(中略)
既存DION会員は、ブランド名変更後も現行のサービスやログインID、メールアドレスは継続して利用できる。ただし、新たにメールアドレスやホームページURLを申し込んだ場合などには、ドメインは「auone-net.jp」になる。
筆者がこのリリースを知ったのはちょっと遅れて10月初め。

いやな予感がした

ので、自宅でKDDIの回線を使っているという友人に一杯おごる約束でいろいろ試してもらって、そのときの画面キャプチャがこれ。

結論: au by KDDIは混乱を拡大させる気マンマンである。

おかしなアカウントを取れてしまうのはdocomo.ne.jpとezweb.ne.jpドメインだけだと思ってコード書いてるそこのプログラマーさん!dion.ne.jp と auone-net.jp も要注意ですよー。

auone-netはともかく、dion.ne.jpドメインにおいて最初に紹介したようなおかしなアカウントを取得できるようになったのがいつごろからなのかは不明。dionはそこそこ古くからやってるサービスなので、もしもサービス開始当初からそうだったとすれば絶対にどこかですでに話題になっているはずだ。だとするとここ1年前後のタイミングのどこかで、アカウント部分の連続ドットやダブルドットをわざと許すような改悪の仕様変更がなされたという可能性が高い。 それはいつ決定され、いつ実行に移されたのか?

そういえば、ナンバーポータビリティ導入のときにauが血迷ってドコモと仕様をあわせてしまうという、まるで意味不明な改悪がなされたのは2006年6月のことだった。 そして今回のauone-net.jp。このテの企業行動は、システムだけじゃなくてサポートやマーケティング上の歩調合わせも必要なので決定から実行までに半年とか1年のスパンがかかるのはよくあることと考えると、いろんなことが起きたタイミングがおおよそ合っている。

いずれにせよ、hogehoge...@xx.dion.ne.jp とか、 hoge...hoge@xx.auone-net.jp といったアドレスに対してメールを送る場合に関しても、この前の記事の冒頭に書いたような現象が発生することは確実である。その混乱の責任は100%、KDDIにある。



さて、 この前の記事は大きな反響をいただいた。 ここから先は、その補足をつらつらと書いていこう。

1. 「メールアドレスのアカウント(@の左側)にはドットは一個も含まれてはいけない」

という誤解をしているらしき内容がコメント欄にいくつか投げ込まれた。
taro.yamada@example.com はOK。
a.b.c@example.com もOK。
hoge..hoge@example.com(ドットが2個以上連続してる)はNG。
hoge.@example.com とか hoge....@example.com (つまりドットが@の直前にある)はNG。
ということである。誤解しないように。

2. 「gmail(Googleの提供する無料Webメールサービス)は連続ドットとかを許可している」

と誤解している人もいるらしい。 そういうことをこのブログのコメント欄に投げたり、友達に話したり、自分のブログなど書いたりする前に、試すべきだろう。30秒で試せることなんだから。 以下はGmailの新規アカウントの取得画面のキャプチャーである。

アカウントの途中にひとつだけドットを使ってみる

許可される。これは正しい動作。

連続するドットを使ってみる

許可されない。これは正しい動作。

アカウントの最後(@の直前)にドットを入れてみる

許可されない。これも正しい仕様。

3. 「ドコモとauだけじゃなく、ソフトバンクもそうらしい」

というのをわざわざメールでもいただいたが、誤解を通り越してガセである。 こことか ここの下の方とか参照。

4. 「RFCのほうを変えればいい」という発想

なかなか斬新でよい(笑)。意見を言うのは自由というやつで、誰だってRFCを提案することができる。 IETFワーキンググループ(作業部会)のメーリングリストに参加して案を投げるとかすればいいんじゃないかな。

「なんで?え?日本の携帯キャリア2社がそんな状況だから?そんだけの理由で、日本の数十倍の数の人が使っているアメリカ、ヨーロッパ、中国、インド、その他各国で運用されているメールシステムや言語処理系の仕様変更を求めるようなRFCを新たに定めるわけ?意味わかんない。Are you nuts?(もっともニュアンスの伝わる意訳=おまえバカか?)」

とか言われてdraft(草案)にもならずに終了するのがオチであると思う。また、考えてみるとそういう提案をすること事態が日本の恥。他の分野でIETF上で議論をしているほかの日本人技術者から見ても迷惑だ。一緒くたに見られてしまう。

ところで、世界各国の人=つまり英語を母国語としない人も沢山いる=が集まる場での、もともと丁寧語の概念も無い英語という言語での議論にはお上品な言い回しなんて一切無いから覚悟したほうがいい。彼らはストレートだ。NOはNO、YESはYES。筆者は本当にare you nuts?が飛び交っているメーリングリストを目の当たりにしたことがある。日本人が日本語でやりとりしているだけの技術系メーリングリストでの遠まわしな言い争いなんてまったくかわいいものだ。

5. 「国内に閉じた話だと思えばいいじゃんべつに」

ネットに国内も国外もない。HotmailにしろGmailにしろ、日本語を含め世界各国の言語でサービスされている。サーバーがどこにあるかすらよくわからないが、少なくともその多くは欧米に設置されている。 つまり、さも「日本のサービス」であるかのように見えるWebサイト上のサービスは実はおおもとはひとつで、カワ(皮)だけが各国語対応なのだ。こうしたサービスは今でも沢山あるし、今後も増える一方で減ることなんて無い。 そうしたサービスでは当然「日本向けにはアドレスの文字パターンの制限をゆるくして。。。」なんて気を利かせることはない。おおもとはひとつ(の仕様に沿っている)だからこそ低価格(無料)かつ安定したサービス提供ができるのだから。 これはHotmailやGmailのようなWebサイト経由のサービスに限らず、パッケージ製品として売られていてPCにインストールして使う形のソフトウェア製品にも言える。

ところで、ちょうど1年ほど前のやや古い記事ではあるが、

「ヤフーはクローズ、iモードはオープン」・ドコモ夏野氏が反論 (IT-PLUS 2006/10)

ヤフーの井上雅博社長は「これまでの携帯のネット利用は昔のパソコン通信と似ており、オープンなインターネットの利便性を生かせていない」とiモードの閉鎖性を指摘。ソフトバンクの孫正義社長は、携帯ポータルの「ヤフー!ケータイ」を通じ無料のコンテンツやサービスを提供することで、「iモードのビジネスモデルは根底から覆される」とアピールしている。

 これに対してiモードの生みの親の一人である夏野氏は、携帯とインターネットとの連携機能を強化している点などを挙げ、「我々はインターネットとも親和性の高いオープンプラットフォーム型」と反論。

しらじらしい。

オープンなところ=インターネット=にもそれなりの標準規格というものがある。電子メールのそのアドレスそのものという超基本的な部分が規格に沿ってない状態をわかっていながらも1999年のiモード登場以来かれこれ8年間もほったらかしのままなのがドコモである。

6. 「ダブルクォートでくくればいいやん」

元記事にも最初からちらっと書いてある回避策である。 一般ピープルなユーザーが求めているのはそんな技術的かつ応急処置的な策ではなくて現実的な方法である。 少なくともこの手法は本書いたり業界紙に記事を書いたりするそこそこの有名人が詳しい周辺説明をほとんど沿えずに肯定的に解釈されかねない形で公開するようなことじゃない。小難しい正規表現とperlやJavascriptのコードを見せびらかしたかっただけちゃうんかと。 ちっとも現実的ではない解決策がさも決定打のように伝播しかねないのがこのテの情報のやっかいなところである。

考えてもみてほしい。

「お好きなアドレスに変更」という画面操作の結果、実際にこういうふうに表示されるのだ(「メール設定確認」という画面においても同様)。 「あなたの新しいメールアドレスは hoge...hoge@docomo.ne.jp です」とはっきりそう表示された以上、それが自分のメールアドレスだと思って当然である。 なのに、
「そのメールアドレス、実は
hoge.....hoge@docomo.ne.jp
ではなくて
"hoge.....hoge"@docomo.ne.jp
って書かなければいけないんですよ、場合によりますが、、、」
なんてことを話したところで 「何言ってんだこのヲタ?」とか思われて険悪なムードになるのがオチである。

7. 「RFCもダブルクォートも意味わかんないよ、どうでもいいからなんとかして。」

そのとおりだ。 RFCだのダブルクォートだのといった単語すらまったく知らないおばあさんであっても「らくらくホン」かなんかの使い方を一生懸命覚えてもらって遠い国に留学中の孫娘(hotmailを使っている)にメールを送ったり、職場のパソコンのMS-Outlookから「今晩遅くなるからご飯いらないよ」と嫁さんの携帯にメールすることを、何を考えるでもなくただ「メールアドレスを正しく打てばできる」ようにするのが技術屋に与えられた使命であり、そこには技術的な議論や説明が入り込む余地も必要もまったくない。まったくないはずなのにこんな話をしなければならない状態を何年も放置して混乱を拡大させているのがドコモとauである。

8. 「RFC違反のメルアドであることが逆に迷惑メール対策として機能してくれちゃうからいい(笑)」

ということを言う人は、下記のように「業務に支障が出てて困ってるんです!」みたいな人に向かって、同じことを言ってあげて欲しい。 ついでに、こうした問い合わせを何年も受け続けているプロバイダ各社やソフトウェア会社、Webサイトのサポートセンターのお姉さんにもだ。 間違いなく「んなこと聞いてねえよ」とキレられるだろう。

9. 「間違った状態を長年続けすぎて修正とテストの工数と費用とサポートコストがとれないんでしょ」

という意見には突っ込みどころが複数あってどこから話したらいいのかよくわからない。 たとえばの話、
  • 5万円の商品を4万円とうっかり書いて何週間かECサイトに掲載していて、その間に注文も何件か入ってた
というミスはネットじゃなくてもよくあることである。
対応策その1:すぐに数字を5万円に修正する。または商品ページそのものかあるいは注文フォーム自体を一時的に閉鎖する
対応策その2:注文してしまったお客にお詫びして断るか、あるいはその客には事情を説明しつつ損を覚悟で商品を発送する
という順序で対処するだろう。こんなのは高校生でも思いつくことで、 まず出血を止めるのがトラブル対応の基本である。 そうやって被害の拡大をまず防いでこそ、そのあとのこと(対策その2)にゆっくり対応できるのだから。

改めて言うまでも無いが、ドコモとauが取るべき対策とは

  • 対応策その1:メールアドレス取得と変更のそれぞれの画面を仕様変更して、連続ドットや@直前ドットを受け付けないようにしておく
  • 対応策その2:既にそういうアドレスを取ってしまった人については順次、広報と案内をしながら変更を促しつつ長めの移行期間を取る。
ということだ。対策その2の過程においては「かくかくしかじか、という理由なんです。ごめんなさい。」とユーザーに謝るしかない。 それが8年間(auの場合は1年半)ほったらかしてきたぶんの甘んじて受けるべきペナルティ。

しかし、ドコモもauも問題を承知していながら対応策その1を取ろうとする姿勢がまったく無い。 auにいたっては携帯分野だけでなく一般PC向けプロバイダサービスにおいても問題を拡大させようとしている。 Web屋として断言できるが、サーバー側のメールアドレス変更画面での文字列のフィルタリング処理を少し変えるだけの話であってそれは大した手間ではない。ユーザー数とかサービス規模の大小はほとんど関係なくやろうと思えばすぐできることなのに、である。

10. 「ブログなんかに書いてないでドコモとauに直接言うべきでは?」

という意見については、そのとおりと考えて、こんなふうに行動に移してくれた人もいる。

[雑記]ドコモでRFC非準拠メールアドレスを取得できてしまう件

直接ドコモに聞いてきた。聞いてきたといっても本社ではなく、そこら辺にあるドコモショップに。結論から言うと、一ユーザーが意見したところで何の力にもならなかった。
(中略)
驚いたのが、国際的な話になってしまうので無理。と、送りたい場合はメールアドレスを変更せよという回答だ。ドコモには3年も前から問い合わせがあり、問題を認識していながら放置していることになる。しかもその理由が国際的な話になってしまうときたもんだ。 RFC2821に準拠していないことを棚にあげておいて、だ。近年中に対策することはあるか?の問いにも無い、ただ打診はしているの一点張り。準拠する気はさらさら無い模様。
詳細はともかくこういう結果になることは上の人もうすうす予想してたのだろう。 それにしても、「Hotmailからメールを送れない問題は国際的な話になってしまうので対応できない。」というのはボケとして新しい。欧米かっ」の向こうを張れるかもしれない。

ということを言うと、「だから、携帯は携帯のなかだけでやりとりできる仕組み(つまりショートメッセージサービス)だと思えばいいじゃない」とかのたまう人もいる。それならそれで、@docomo.ne.jpなんてドメインをつけるんじゃねえよと。(以下略)

マスコミ報道に期待?いやいや。こんな説明しづらくて影響範囲が中途半端な形に広い話でしかもターゲットが大口の広告主様となると、まともな記事になることはまず期待できない。せいぜいInternetWatchの一般記事ではなくてやじうまWatchという三面記事的なところで取り上げられる程度である。

中の人の良心に期待?いやいや。そんなものが機能してれば8年もほったらかされやしない。

  1. 去年の4月ごろに筆者がDoCoMoの説明にある「RFCに準拠しています」はウソという記事を書くと
  2. その2週間後には「RFCに準拠しています」の部分だけを削除する
といった程度の後ろ向きな行動の後にそれっきりになってしまうあたりが彼らの自浄作用の限界を示している。そういえば先週のログ解析には、nttdocomo.co.jp(proxy**.docomo.ne.jpじゃないよ)からのアクセスが少し増えていた。ドコモとauの中の人、見てるー?ヤッホー。

11.「有名な企業だもん。きっと、なにか理由があってもう変更できないんだよ」

こういっちゃなんだが、おめでたい。なんらかの詐欺にひっかかりやすいタイプなので注意したほうがいい。あるいは時事ニュースを暇つぶしにしか読んでない人である。暇つぶしが悪いとは言わないが、今起きていることを他のことに当てはめて考えてみるということをしないとニュース見てる意味が無い。

雪印、三菱自動車、最近では赤福に吉兆。有名どころがずらり。彼らに「理由」はあったのだろうか? そりゃつきつめればカネなのだろうが、そこまでしないと本当に潰れちゃうほどだったかというとそうでもなかろう。 で、問い詰めても問い詰めても最後には「私は寝てないんだよ!(雪印社長の名言)」といった意味不明な理由がでてくるだけ。

そう、理由なんて無いのだ。大したせっぱつまってもいない組織なのに、何かの拍子におかしなことをはじめて、時がたつにつれて周りの空気のほうが変わってきていることにも薄々気づいているくせに「わかっちゃいるけどやめられない♪」状態に陥るのは、コトの大小を問わず、同じなのである。これはゲームじゃないよな現実だよなと心の奥底では理解しているのに結局ゲームオーバーまでやってしまうのがリアル版黒ひげ危機一髪の不思議なところ。

12. 誰か偉い人に苦言を言ってもらうとか?

とりあえずの平和的な解決には意外とそれが一番効果的なんじゃないかなと筆者もそう思ってる。 スーダラ節唄ってる中の人には期待できない。携帯電話を「電話」としか捉えることができないお役人にも期待できない。 だとすればここはひとつ、たとえば村井教授あたりのクラスの方にこの件について軽く講義していただければと思う。 ちなみに、電子メールのアドレスについてではなく文字セットの規格の話ではあるがRFC1468は氏の手によるものだ。Standard(標準)ではなくInformation(参考情報)に分類されるものではあるが、現在も巷のメール関連のソフトウェアのほとんどがこの規格に沿ってコーディングされている。

こういう偉い人の近くにいる人は、「出番ですよ」と伝えていただけると幸いである。あなたのような肩書きはこういうときのためにあるのだ、と。それが偉い先生の近くにいる人間の役目でもあるのだから。

なお、学生さんの場合にはこのブログのURLを添えて「こんな話があるらしいっす」とだけ伝えるような無礼なマネを間違ってもやらないように。それは目上の人にちょっと込み入った話を伝える方法として正しくない。きちんと周辺情報を調べて学生らしくレポート用紙にでもまとめるかプレゼンテーションをするべきだ。 この件だけで卒業論文の材料にするには不足だろうが、 インターネット上において標準規格に沿わない状態を是正せずに長く続けるとどういう事態になるかというちょっとしたフィールドワークにはちょうどいいだろう。



最後に、メールアドレスのアカウント部分の決定ルールとはどうあるべきか?という話をしておこう。 といってもなんのことはない、他の事業者を参考にすればいいだけのことだ。

ソフトバンクモバイルの場合

ドコモとauの話のだから、例としてソフトバンクをまずあげておくべきだろう。
メールアドレス設定|SoftBank
  • アカウント名の先頭に数字はご利用できません。(英字のみ。)
  • 「.」をアカウント名の最後(@マークの直前)にご利用いただけません。
  • 「.」の連続でのご利用はできません。
ということで、きちんと対応されている。この仕様はソフトバンクがまだvodafoneだった時代から変わっていないことは 筆者の過去記事の下のほうのキャプチャからもわかる。

niftyの場合

@niftyユーザー名 ご入力上の注意(←これがアカウント部分、つまり@の左側の規則にあたる)
  • 2~32文字で入力してください。
  • 使用できる文字は、半角英数字、ハイフン( - )、アンダーバー( _ )、ピリオド( . )です。
  • @niftyユーザー名は、英大文字と英小文字が区別されません。
  • ピリオドは、末尾や連続での使用はできません。
  • 先頭の1文字は必ず英文字にしてください。
  • 英字3桁+数字5桁の組み合わせと英字4桁+数字4桁の組み合わせはできません。
      (禁止形式例:abc12345 wxyz9876)
ちゃんと連続ドット、@直前ドットの禁止が考慮されている。

biglobeの場合

BIGLOBEメール|BIGLOBEメールの仕様
ご注意
  • 先頭の文字には、半角英小文字または半角数字を使用してください。
  • .(ドット)の連続や、最後の文字に.(ドット)を使用することはできません。
  • 既に他の方が使っているメールアドレスは取得できません。
同じく連続ドット、@直前ドットの禁止が考慮されている。

IIJ4Uの場合

メールに関するQ&A
設定可能なメールアカウント名(メールアドレスの"@"より左側の文字列)には、以下の制限があります。
  • アカウント名の長さは、2文字以上8文字以内です。
  • 使用できる文字は以下のとおりです。
    • "a"~"z"の半角英小文字
    • "0"~"9"の半角数字
    • "-"(半角ハイフン)
  • 1文字目は英小文字のみ使用できます。
そもそもアカウント部分にドットをまったく使わせないようにすることで余計なトラブルを防止しているということだ。

wakwak(NTT-ME系列)の場合

WAKWAK - メールサービス
ご指定いただけるアカウントは3文字以上16文字以内で、使用できる文字は「小文字英数字」「ハイフン (-)」「アンダーバー (_)」「ピリオド (.)」です。また、先頭文字は英字のみで、「ハイフン」「アンダーバー」「ピリオド」の前後は英数字となります。
表現の仕方こそほかと違うが、結果的に連続ドットや@直前ドットが禁止されている。ハイフンやアンダーバーが連続するのも間違いのもとなのでそれをも防げるようになっている。例えば a____b@example.comとかいうアドレスにしてしまったとして、アンダーバーがいくつつながってるかすぐわかんないでしょ?(笑)ということ。

Yahoo!メールの場合

Yahoo!メールの場合は、そのアカウント部分の文字ルールは、Yahoo!IDの文字ルールと等価である。 そしてそのYahooJapan IDの取得画面は次のように書かれている。
https://edit.yahoo.co.jp/config/eval_register
Yahoo! JAPAN ID
・ 最初の文字はアルファベット
・ 記号は、アンダーバー( _ )のみ使用可能です
混乱を呼ばないように、そもそも記号の利用自体が大幅に制限されていることがわかる。

GMailの場合

最初に紹介したとおり。

こうしてみると、携帯電話/パソコン向けサービスを問わず「メールアドレスを発行/提供する」というサービスをしている事業者のなかで、 連続ドットや@直前ドットを許すようなおバカことをしているのはドコモとau(とdion)だけで、 しかも『「.」(ピリオド)をアドレス内で連続使用したり、アドレスの最後に設定すると、一部のプロバイダとメールを送受信できない場合があります。』などと今となっては完全に間違った言い訳までもが共通しているというマヌケな姿(この前の記事を参照)が、あらためて浮かび上がってくるのである。

see also:

ドコモもauもいいかげんにメールアドレス設定の仕様を直せ。

ほんの2ヶ月ほど前。2007年9月17日。MS-Office2003に対するサービスパック3が公開された。 しかしこのパッチをあてると、Outlook2003において次のようなトラブルが発生する。

初質問・メールのトラブル (答えてねっと 2007/10/7)より:

ある日、友達から来たメールなんですけど、そのメールを返信しようとメールを作成して、送信しました。 送受信をクリックしたら、あるメールが届きました。 しかも、僕の返信したメールと同時刻の受信日時になっていて、差出人は{システム管理者}で、宛先には僕のユーザー名が書いてあって、件名にはなんと、{配信不能}と・・なんだろうこんなことは今までなかったのに・・・・と思いつつ、そのメールをあけると本文には、「このメールは受信者全員または、一部に届きませんでした。」との一文が。
(中略)
ちなみに、友達のメールアドレスは公開できませんが、(携帯)のアドレスです。
(中略)
たかしtsさん。回答ありがとうございます。 本題ですが、そういえば友達のメールアドレスに「.」ドット連続が入っています! OfficeSP3は3日前にUPdateされました・・・。

そう。つまり、これ↓にひっかかるようになる。

メール アドレスの @ より前にピリオドがあるなど RFC に準拠していない宛先に Outlook からメッセージを送信できない(support.microsoft.com 2007/8)より:

Microsoft Office Outlook 2003 および Microsoft Office Outlook 2007 からメールアドレスの @ の直前にピリオド (.) がある、または @ より前でピリオドが連続するなど RFC (Request for Comments、インターネット技術標準化委員会が提唱している規格) に準拠していないフォーマットのメール アドレスにメールを送信した場合、配信エラーとなり、以下の配信不能メールが返されます。
件名
配信不能 : メールの件名が表示されます。

本文内容
このメールは、受信者全員または一部に届きませんでした。
回避策はもちろん無い。これはOutlookの仕様であり、かつ、「電子メール」そのものの、もともとの仕様だからだ。 そんなおかしなメールアドレスを取得できてしまうサービス提供者=ドコモとau=に100%の責任がある。

下記のような話はすべて同じことであり、全ては氷山の一角である。

上にあげたケースは(困っている人から見て)原因が判明してるからまだいいものの、 下記のようにまだ「なんでだろう?」状態の人や、違う原因だと思ってしまっている人は、 ゴマンといる。混乱が混乱を呼んでいる。

ところが、ドコモもauも、下記のような説明でのらりくらり。

メールアドレス変更 | お知らせ | NTTドコモ(画像こちら)

「.」(ピリオド)をアドレス内で連続使用したり、アドレスの最後に設定すると、一部のプロバイダとメールを送受信できない場合があります。

KDDI au: 迷惑Eメール防止方法 > Eメールアドレス変更方法(画像こちら)

「. (ピリオド/ドット)」をアドレス内で連続使用したり、@マーク直前に設定すると、一部のプロバイダーとメールを送受信できない場合があります。

メール基本仕様 (dion (h以降) ドメインの仕様): メールを使おう | au one net (画像こちら)

※1 「. (ピリオド/ドット)」をアドレス内で連続使用すると、一部のプロバイダーとメールを送受信できない場合があります。

筆者注!: KDDIはdionブランドで展開しているパソコンで使用する通常のプロバイダサービス=dionにおいても、 例えば「***.@**.dion.ne.jp」「**..**@**.dion.ne.jp」のような問題のある形式でのメールアドレスの取得ができてしまうという致命的な欠陥を抱えている。これは筆者が関わるとあるWebサイトの運営サポートの過程でも判明した仕様。

前にも書いたが、この書き方は「一部のプロバイダーのほうに責任がある」と読めるのがミソ。 なにしろ書いてあるのが天下のドコモ様とau様のWebサイトなのだから。

こと今に至っては、「一部のプロバイダとメールを送受信できない場合があります」などという話は大ウソであり明らかに説明不足と言わざるをえない。

こう書くべきだろう。
  • 「. (ピリオド/ドット)」をアドレス内で連続使用したり、@マーク直前に設定すると、一部のプロバイダーとメールを送受信できない場合があります。
  • また、「. (ピリオド/ドット)」をアドレス内で連続使用したり、@マーク直前に設定すると、あなた(にメールをくれる相手)が契約しているのがどのようなインターネットプロバイダーであろうとも、その人がOutlook2003(sp3以上)またはOutlook2007といったメールソフトを使用している場合には、メールを送受信できません。
  • あるいは、あなたがMSN HotmailというWebメールサービスを使っている場合にもやはり上記と同様にメールを送受信できません。
  • 連続ドット、@直前ドットを含むメールアドレスを設定すると、 企業の業務用メールシステムなどで、メールサーバーとしてMicrosoft Exchangeサーバーをご使用の場合にも、やはり上記と同様にメールを送受信できません。
  • 連続ドット、@直前ドットを含むメールアドレスを設定すると、 マイクロソフト製品によらず、RFC標準に正確に準拠している他のクライアント/サーバーソフトウェアやASPサービスにおいても同様の不具合が発生する可能性があります。
  • 上記のすべてについて、RFCに準拠しないメールアドレスを設定できてしまうようなシステムを作ってしまっている私どもに責任がございます。申し訳ありません。

そうそう。上にも書いたとおり、Outlookのようなクライアントソフトだけでなく、ホットメールのようなASPサービスにおいても次のようなことになっている。

MSN ヘルプ - 重要なお知らせ @ の直前にピリオドがあるなどの RFC に準拠していないアドレスとの送受信について

いつも MSN をご愛顧いただき誠にありがとうございます。

MSN Hotmailのメールアカウントと、xxxx.@xxxxxx や xx..xx@xxxxxx のようなピリオド( . )がメール アドレスの最後についていたり、ピリオドが連続しているようなアドレスとの間でメールを送受信する場合に、適切に動作することができません。

この現象は、それらのメールアドレスがRFC2821に準拠したものではないために起こります。

RFC2821 では、"@" の前の文字列をピリオド ( . ) で区切ることを許可しておりますが区切り文字であるピリオドや "@" などを連続して使用することを許可しておりません。
従いまして、このようなアドレスを持ったメッセージの送受信を拒否しています。 またMSN Hotmailのアカウント名にそれらRFC2821に準拠してないものを使用することは認めておりません。

MSNおよびMicrosoftは、インターネット通信における相互接続性を維持するために技術的な根拠であるRFCへの準拠は必要な対応であると認識しており、準拠していないものに対する相互接続性は、その保証をすることができないため認めておりません。

以上のことから、RFCに準拠していないアドレスとの送受信は行っておりませんことをご理解いただきますようお願い申し上げます。

引き続きMSNをご愛顧いただきますよう重ねてお願い申し上げます。

[2006.10.12 掲載]
過去にはいろんな規格やら業界標準をやたら無視してきたマイクロソフトではあるが、ここではめずらしく強い調子。いやもちろんこれは、インターネットに関係するソフトウェアやサービスを提供する者として、とてもまっとうな態度である。 まっとうじゃないのはドコモとauのほう。

問題は既製品のソフトウェアだけに限らない。MSが提供するプログラミング言語とそのライブラリの仕様自体が、このようなRFC違反のメールアドレスを、許可しないようになっている。

2006-09-07 - NAgiler航海日誌v2

.NETだとMailMessageクラスの送信先アドレスとして、上記のようなRFC非準拠のアドレスを設定した時点で、FormatExceptionが発生してしまいます。SmtpClientクラスでそんなアドレスを使っても同様の動き。しょうがないのでSystem.Net.Socketsのライブラリを利用してSMTPの通信を自分でゴリゴリと記述してみたけど、今度は「501 5.5.4 Invalid Address」というエラーメッセージでSMTPサービスにはじかれる。これはWindows付属のSMTP自体がRFC非準拠のアドレスをはじくみたいですね(↓)
(中略)
というわけで結論.
■ 携帯メールへメール送信する必要があり、"."の連続や@の前に"."が存在するメールアドレスだろうとメールを送らなきゃいけない場合
Windows付属のSMTPサービスはおろかSystem.Net.Mailも使わずにSystem.Net.Socketsを使ってゴリゴリと...(略)
■ RFCに準拠しないアドレスは気にしなくても良い場合
Windows付属のSMTPサービスもSystem.Net.Mailを使ってもOK!!

ってとこでしょうか。RFC非準拠のアドレスでもはじかないSMTPサービス探さなきゃ。(すごい矛盾)
.NETでプログラミングされたあらゆるソフトウェアがこうした問題にひっかかる。 さあ、プログラマーのみなさんご一緒に。「いいかげんにしろよドコモとau。」

さて、この話はもう何年も前からこのブログだけでなくほかのいろんなところで話題になっている。 ところがドコモは一向に改善の気配をみせないばかりにでなく、auにいたってはナンバーポータビリティ導入のときに 血迷ってドコモと仕様をあわせてしまうという、まるで意味不明な改悪がなされた。 一方でMS-Office製品はセキュリティ強化の一環もあっていろんな共通仕様を忠実に守るようになった。 そんなこんなで少しずつ傷口を広げつつ今に至り、もうのっぴきならないところまで来てしまっているのが現在の状況なのだ。

こういうことを書くとRFC原理主義だねだのなんだの言う人がいるが、そんな話は的外れである。

  • 問題のようなアドレスを持つ携帯(やdionのメールアドレス)には、ホットメールからは送ることが絶対に出来ない。(修正される見込みはほとんどない)
  • プロバイダがYahooBBだろうとBiglobeだろうとniftyだろうと他のどこだろうと、 Outlook2003(SP3)またはOutlook2007を使っている人は送ることが絶対に出来ない。修正パッチが出る可能性はほぼゼロ。アカウント部分をダブルクォートでくくれば出来るがそんな面倒なことをやれとでも?
  • ExchangeServerを使っている企業の中の人は送ることが絶対に出来ない。(修正パッチが出る可能性はほぼゼロ)
  • メールサーバにpostfixを使っているプロバイダやWebサイト運営者なら、postfixにちょっとした設定を変更するだけでなんとか対応できるが、わざわざRFC違反の状態にするというのは技術屋の抵抗は強いはず。そもそもメールサーバ側でなんとかしたとしても、Outlookのようにクライアント側でこの状態だともうどうしようもない。
ドコモもauも、ユーザーやメールサーバ管理者が直面しているこの現実をどうしてくれるんだ?ということなのだから。

これ以上、「一部のプロバイダとメールを送受信できない場合があります。」という何の免罪符にもならないまやかしの言い回しが劣化コピーのごとく出回ってしまわないことを祈るばかりだ。

とりあえずドコモの携帯で確認したが、2007年11月現在のいまも、***.@docomo.ne.jpとか**....***@docomo.ne.jpといったメールアドレスの設定/取得は可能なままである。

see also:

続きがあります→ドコモもauもいいかげんにメールアドレス設定の仕様を直せ。の続きと補足

RFCの訳は「ご意見お待ちしております」では実はない。 もどうぞ。

PostgreSQLの配列データ型とGINインデックスを使って高速検索する

例えばレストランの検索サイトを思い浮かべてみよう。 「ぐるなび」とかそういうやつ。

  • 場所は必ず日比谷
  • 料理は必ずイタリアン
というふうにガッチリと検索キーを決めているユーザーは すごく少ないはずだ。 かといって単に最寄り駅名だけで検索すると 「1500件ヒットしました」とか言われてしまうのでそれでは選びようも無い。 そこで、検索条件をある程度緩めたり絞りこんだりを繰り返すことになる。
  • 場所は四谷、市ヶ谷、飯田橋、御茶ノ水、秋葉原、浅草橋 (つまりこの人は総武線沿線が便利)
  • 料理はイタリアン、フレンチ、中華(なんでもいいからおいしいもの)
みたいな感じの広めの検索条件を考えているのが 実際のユーザー像ひとつだろう。(あくまでパターンのひとつ)

一方で、レストラン情報を格納しているテーブル群は どんな構造になっているだろう?

  • 最寄り駅:都心は路線が入り乱れている。 地下鉄丸の内線の小川町とJR山手線の神田なんて目と鼻の先だ。 市ヶ谷と飯田橋の中間あたりに位置するレストランだってあるだろう。 したがってひとつのレストランに対して最寄り駅が複数設定されている。 (1対Nの関係)
  • 料理ジャンル:イタリアンと中華が同居しているレストランなんてありえないので 1レコードにひとつ(1対1)としてしまいがちだが、 「和食」と「和風居酒屋」の両方のジャンルでヒットするようにしておきたいという 気持ちもあるだろう。そこでこれも1対Nだとする。

1対Nの関係にある情報はそれぞれ別のテーブルに格納(正規化)するのが リレーショナルデータベースの基本である。 上の話を統合すると、レストラン情報を格納するテーブルは下記の3つの テーブルで構成される。

  • レストランテーブル(コレが親テーブル。1対Nの1の側)
  • 最寄り駅テーブル(子テーブル。1対NのNの側)
  • 料理ジャンルテーブル(同上)
本当は駅マスタテーブル、ジャンルマスタテーブルetcだって もちろん必要となるだろうがここでは省略。

ではこのテーブル群を、上のほうで書いたような広めの検索条件で検索してみる。

SELECT
    レストランテーブル.レストラン名
FROM
    レストランテーブル, 最寄り駅テーブル, 料理ジャンルテーブル
WHERE
    レストランテーブル.レストランID = 最寄り駅テーブル.レストランID
    AND
    レストランテーブル.レストランID = 料理ジャンルテーブル.レストランID
    AND
    最寄り駅テーブル.駅コード IN ( 
        20,21,22,23,24 /* 20が四谷、21が市ヶ谷と思ってね */
    ) 
    AND
    料理ジャンルテーブル.ジャンルコード IN ( 
        5,6,7 /* それぞれの番号がイタリアン、フレンチ...*/
    ) 
IN句じゃなくてEXIST句のほうがとか、 USING句のほうがすっきりだとか、 条件によってはOR句じゃないと難しくね?とか、 イコールの右辺と左辺入れ替えたほうがどうだろう? とかいった細かい点は目をつむっていただきたい(苦笑)。 あくまで話をわかりやすくするための例なので。

とにかく、ここで配列データ型の登場である。

  1. 教科書どおりに正規化されたこれら3つのテーブルは、 実はPostgreSQLの配列データ型を使うとひとつのテーブルに集約できる。
  2. それらのカラムには一般に使われるB-Tree形式のインデックスではなく GIN形式のインデックスを張ることができ、
  3. さらに配列関数、配列演算子を使って上記のSQL文を 記述しなおしたものを走らせると、
  4. かなり高速に検索できるようだ。

実際に試してみる。 テーブル構造はこんな感じ。

/*
 レストラン情報テーブル(普通のリレーショナルなやつ。
 3テーブルで構成。
*/
CREATE TABLE RESTAURANT (
    REST_ID     INT4            NOT NULL, -- レストランのID(通し番号)
    NAME        VARCHAR(64)     NOT NULL  -- レストランの名前
);
-- 最寄り駅テーブル
CREATE TABLE RESTAURANT_MOYORIEKI (
    REST_ID     INT4        NOT NULL,
    EKI_ID      INT4        NOT NULL
);
-- 料理ジャンルテーブル
CREATE TABLE RESTAURANT_JANRU (
    REST_ID     INT4        NOT NULL,
    JANRU_ID    INT4        NOT NULL
);

/*
 レストラン情報テーブル(配列データ型を活用したバージョン)
 1テーブルのみで構成される。
*/
CREATE TABLE RESTAURANT2 (
    REST_ID         INT4        NOT NULL, -- レストランのID(通し番号)
    NAME            VARCHAR(64) NOT NULL, -- レストランの名前
    MOYORIEKI_ARRAY INT4[]              , -- 最寄り駅コード数値の配列データ型
    JANRU_ARRAY     INT4[]                -- ジャンルコード数値の配列データ型
);
上記のテーブルに対して次のような想定でデータをつっこんでおく。
  • レストランは10万件
  • 駅は200個
  • 料理ジャンルは10種類
  • レストラン1件あたり、最寄り駅は200個からランダムに3個。
  • レストラン1件あたり、ジャンルは10種類のうちランダムに2個。

まず普通のテーブルのほうを普通に検索してみる。 まだインデックスはなにも張ってない状態。

testdb=> explain analyze
testdb-> select
testdb->     r.rest_id
testdb-> from
testdb->     restaurant r
testdb->     inner join restaurant_moyorieki m using(rest_id)
testdb->     inner join restaurant_janru j using(rest_id)
testdb-> where
testdb->     m.eki_id in (48,174)
testdb->     and
testdb->     j.janru_id in (4,5)
testdb-> ;
                                                                 QUERY PLAN               
--------------------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=9096.03..12723.21 rows=1045 width=4) (actual time=296.193..406.993 rows=1257 loops=1)
   Hash Cond: (j.rest_id = r.rest_id)
   ->  Seq Scan on restaurant_janru j  (cost=0.00..3481.00 rows=36195 width=4) (actual time=0.043..84.441 rows=40084 loops=1)
         Filter: (janru_id = ANY ('{4,5}'::integer[]))
   ->  Hash  (cost=9059.93..9059.93 rows=2888 width=8) (actual time=296.103..296.103 rows=3092 loops=1)
         ->  Hash Join  (cost=3377.00..9059.93 rows=2888 width=8) (actual time=174.980..293.434 rows=3092 loops=1)
               Hash Cond: (m.rest_id = r.rest_id)
               ->  Seq Scan on restaurant_moyorieki m  (cost=0.00..5221.00 rows=2888 width=4) (actual time=0.037..94.158 rows=3092 loops=1)
                     Filter: (eki_id = ANY ('{48,174}'::integer[]))
               ->  Hash  (cost=1736.00..1736.00 rows=100000 width=4) (actual time=169.302..169.302 rows=100000 loops=1)
                     ->  Seq Scan on restaurant r  (cost=0.00..1736.00 rows=100000 width=4) (actual time=0.024..81.049 rows=100000 loops=1)
 Total runtime: 407.983 ms
(12 rows)
400ミリ秒ほどかかる。

次に配列データ型をつかって作ったテーブルのほうを数字だけ変えた条件で。

testdb=> explain analyze
testdb-> select
testdb->     r2.rest_id
testdb-> from
testdb->     restaurant2 r2
testdb-> where
testdb->     r2.moyorieki_array && array[43,125]
testdb->     and
testdb->     r2.janru_array && array[3,4]
testdb-> ;
                                                  QUERY PLAN                              
---------------------------------------------------------------------------------------------------------------
 Seq Scan on restaurant2 r2  (cost=0.00..3088.00 rows=2 width=4) (actual time=0.256..69.804 rows=1156 loops=1)
   Filter: ((moyorieki_array && '{43,125}'::integer[]) AND (janru_array && '{3,4}'::integer[]))
 Total runtime: 70.400 ms
(3 rows)
70ミリ秒。インデックス張ってなくてもこの性能。 テーブル間のJOIN(結合)が無いから効率がよいのは当然だが。

次に、それぞれインデックスを張ってみる。こんな感じ。

/*
 普通のリレーショナルなやつ用。
*/
DROP INDEX IF EXISTS I_RESTAURANT_ID;
DROP INDEX IF EXISTS I_REST_ID_MOYORIEKI;
DROP INDEX IF EXISTS I_EKI_ID_MOYORIEKI;
DROP INDEX IF EXISTS I_REST_ID_JANRU;
DROP INDEX IF EXISTS I_JANRU_ID_JANRU;

CREATE INDEX I_RESTAURANT_ID        ON RESTAURANT (REST_ID);
CREATE INDEX I_REST_ID_MOYORIEKI    ON RESTAURANT_MOYORIEKI (REST_ID);
CREATE INDEX I_EKI_ID_MOYORIEKI     ON RESTAURANT_MOYORIEKI (EKI_ID);
CREATE INDEX I_REST_ID_JANRU        ON RESTAURANT_JANRU (REST_ID);
CREATE INDEX I_JANRU_ID_JANRU       ON RESTAURANT_JANRU (JANRU_ID);

/*
 配列型のテーブル用。まずはこっちも普通に(Btreeで)はる。
*/
DROP INDEX IF EXISTS I_RESTAURANT_ID_2;
DROP INDEX IF EXISTS I_MOYORIEKI_ARRAY;
DROP INDEX IF EXISTS I_JANRU_ARRAY;

CREATE INDEX I_RESTAURANT_ID_2  ON RESTAURANT2 (REST_ID);
CREATE INDEX I_MOYORIEKI_ARRAY  ON RESTAURANT2 (MOYORIEKI_ARRAY);
CREATE INDEX I_JANRU_ARRAY      ON RESTAURANT2 (JANRU_ARRAY);
これでさっきと同じ検索をする。

まずは普通のテーブルのほう。

testdb=> explain analyze
testdb-> select
testdb->     r.rest_id
testdb-> from
testdb->     restaurant r
testdb->     inner join restaurant_moyorieki m using(rest_id)
testdb->     inner join restaurant_janru j using(rest_id)
testdb-> where
testdb->     m.eki_id in (48,174)
testdb->     and
testdb->     j.janru_id in (4,5)
testdb-> ;
                                                                          QUERY PLAN      
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=5764.08..7343.70 rows=1045 width=4) (actual time=187.404..244.678 rows=1257 loops=1)
   Hash Cond: (j.rest_id = r.rest_id)
   ->  Bitmap Heap Scan on restaurant_janru j  (cost=577.02..2010.46 rows=36195 width=4) (actual time=9.544..38.947 rows=40084 loops=1)
         Recheck Cond: (janru_id = ANY ('{4,5}'::integer[]))
         ->  Bitmap Index Scan on i_janru_id_janru  (cost=0.00..567.97 rows=36195 width=0) (actual time=9.238..9.238 rows=40084 loops=1)
               Index Cond: (janru_id = ANY ('{4,5}'::integer[]))
   ->  Hash  (cost=5150.96..5150.96 rows=2888 width=8) (actual time=177.794..177.794 rows=3092 loops=1)
         ->  Merge Join  (cost=1734.38..5150.96 rows=2888 width=8) (actual time=23.220..174.715 rows=3092 loops=1)
               Merge Cond: (r.rest_id = m.rest_id)
               ->  Index Scan using i_restaurant_id on restaurant r  (cost=0.00..3123.26 rows=100000 width=4) (actual time=13.071..99.232 rows=99997 loops=1)
               ->  Sort  (cost=1734.38..1741.60 rows=2888 width=4) (actual time=10.124..11.872 rows=3092 loops=1)
                     Sort Key: m.rest_id
                     ->  Bitmap Heap Scan on restaurant_moyorieki m  (cost=54.91..1568.38 rows=2888 width=4) (actual time=1.477..7.925 rows=3092 loops=1)
                           Recheck Cond: (eki_id = ANY ('{48,174}'::integer[]))
                           ->  Bitmap Index Scan on i_eki_id_moyorieki  (cost=0.00..54.19 rows=2888 width=0) (actual time=1.095..1.095 rows=3092 loops=1)
                                 Index Cond: (eki_id = ANY ('{48,174}'::integer[]))
 Total runtime: 245.447 ms
(17 rows)
インデックススキャンが走るようになり、速度も幾分速くなった。

次に配列データ型を使ったテーブルのほう。

testdb=> explain analyze
testdb-> select
testdb->     r2.rest_id
testdb-> from
testdb->     restaurant2 r2
testdb-> where
testdb->     r2.moyorieki_array && array[31,159]
testdb->     and
testdb->     r2.janru_array && array[2,4]
testdb-> ;
                                                  QUERY PLAN                              
---------------------------------------------------------------------------------------------------------------
 Seq Scan on restaurant2 r2  (cost=0.00..3088.00 rows=2 width=4) (actual time=0.108..67.081 rows=1166 loops=1)
   Filter: ((moyorieki_array && '{31,159}'::integer[]) AND (janru_array && '{2,4}'::integer[]))
 Total runtime: 67.732 ms
(3 rows)
インデックスは確かに張ってあるのだが、使われない。したがって速度もさっきと変わらない。 この原因については詳しくは調べていないが、 配列データ型とB-Treeインデックスとの組み合わせの向き不向きかなあ。 検索条件の与え方でももちろん変わってくるかもしれないが。

そこで、さっきのB-Treeインデックスを削除して、GINインデックスで新たに張りなおしてみる。

DROP INDEX IF EXISTS I_MOYORIEKI_ARRAY;
DROP INDEX IF EXISTS I_JANRU_ARRAY;
CREATE INDEX I_MOYORIEKI_ARRAY  ON RESTAURANT2 USING GIN (MOYORIEKI_ARRAY);
CREATE INDEX I_JANRU_ARRAY      ON RESTAURANT2 USING GIN (JANRU_ARRAY);
これで、さきほどのSELECT文を値だけ変えて流してみる。
testdb=> explain analyze
testdb-> select
testdb->     r2.rest_id
testdb-> from
testdb->     restaurant2 r2
testdb-> where
testdb->     r2.moyorieki_array && array[67,101]
testdb->     and
testdb->     r2.janru_array && array[5,6]
testdb-> ;
                                                              QUERY PLAN                  
--------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on restaurant2 r2  (cost=28.28..36.10 rows=2 width=4) (actual time=15.790..18.862 rows=1059 loops=1)
   Recheck Cond: ((janru_array && '{5,6}'::integer[]) AND (moyorieki_array && '{67,101}'::integer[]))
   ->  BitmapAnd  (cost=28.28..28.28 rows=2 width=0) (actual time=15.555..15.555 rows=0 loops=1)
         ->  Bitmap Index Scan on i_janru_array  (cost=0.00..8.01 rows=500 width=0) (actual time=13.643..13.643 rows=37819 loops=1)
               Index Cond: (janru_array && '{5,6}'::integer[])
         ->  Bitmap Index Scan on i_moyorieki_array  (cost=0.00..20.02 rows=500 width=0) (actual time=1.440..1.440 rows=2933 loops=1)
               Index Cond: (moyorieki_array && '{67,101}'::integer[])
 Total runtime: 19.479 ms
(8 rows)
かなりのスピードUP。

以下は、ランダムな検索条件を与えながら100回ほどSELECTし、 その処理速度の90%tileで平均値を取った結果である。

  普通のリレーショナルなテーブル構造 + B-Treeインデックス 配列データ型を使ったテーブル + GINインデックス
処理スピード平均(ms) 279 38
ざっと7倍速いという結果になった。 なお、普通のテーブルへの検索結果と配列データ型を使ったテーブルへの検索結果に 違いが発生してないかを調べるため、レストランID(REST_ID)だけをDISTINCTで 重複の無いように出力させ、とりあえずその数を照らし合わせた。 100回のテストで食い違いは発生していなかった。

see also:

そういえばここ一週間くらい*.postgresql.jpのサーバが全て死んでて困る。

アドセンスの国産版(?)のマッチスマートあっさりサービス終了

「そのWebページのコンテンツを勝手に解析して、コンテンツにあった広告を送り込んで表示する」という手法はGoogleの専売特許というわけでもなく、国内でも類似のサービスはあった。たとえばマッチスマート。しかし、2006年8月のサービス開始から1年を経たところで

【重要】マッチスマート サービス終了のお知らせ

日頃から弊社サービスのマッチスマートをご利用いただきまして、誠にありがとうございます。 弊社では2006年8月31日から入札方式によるクリック課金型の広告配信サービスとしてマッチスマートをご提供してまいりました。 しかしながら、外部開発元から提供を受けている基幹システムについて、当初想定しておりませんでした不具合が相次いだため、様々な検討を重ねた結果、2007年12月12日(水)17:00をもって本サービスを終了することと致しました。そして、現在マッチスマートをご利用いただいておりますお取引先様には、ヤフー株式会社の子会社であり、コンテンツ連動型広告配信サービスを提供している株式会社ブレイナーのサービスをご案内させて頂くことと致しました。
あえなくサービス終了。 目立った営業活動も見たことがないし、要するにgooleアドセンスに勝てなかったと。

システム不具合の多発というよりは要するに外注先のWebシステム屋をうまくハンドリングできず、一方で営業もうまくいかなかったのかな。ブレイナーというのはよく知らない。

なんだかなんだか。

↓「以下の要求をお願いしよう」とする先はつまりFind Jobをやっているmixi社なのかそれとも。。。?ってあたりにも少々の興味を感じるもののそれはともかく。

F's Garage:FindJobの有料テキスト広告の件について。

なので、次回の更新の際には以下の要求をお願いしようと思っています。
  • 誤解を受けるのでラベルの文言を変更してください。
  • 社名を出すなどして、今の検索キーワード的な文章ではなく、広告として適切だと思われる文章でなら、つまり、F's Garageを広告のパートナーとして認めていただけるなら掲載の継続をしたいです。

いえいえいえいえ。そんな面倒くさいことを考える必要なんてまるでないかと。

ウェブマスター向けヘルプ センター - 有料リンクを Google に報告する必要があるのはなぜですか。

すべての有料リンクが Google のガイドラインに違反するわけではありません。 リンクの売買も、検索結果の操作でなく宣伝を目的として行われる限り、ウェブ上での通常の経済活動となります。 広告として購入したリンクでは、そのことを明示する必要があります。 この処理は、以下のようないくつかの方法で行えます。
  • rel="nofollow" 属性を <a> タグに追加する
  • robots.txt ファイルによって検索エンジンからブロックされる中間ページにリンクをリダイレクトする

ということで、nofollow属性入れるだけらしく。業界の方でnofollowを知らない人は少ないと思っていたのですが。

いえいえもちろんこんなものは検索エンジン(主にGoogle)側の都合でしかないことはまったくもって確か。 っていうか、いま朝の四時。酔ってるだけ。ええもう。

see also: