いしなお!
2006-07-21 [長年日記]
_ [1470.net][Zend_Cache][Zend Framework] どうもキャッシュの更新状況がおかしいなーと思ったら
Zend_Cacheのmemcachedバックエンドってタグ機能サポートしてないのか……。どうしたもんかなー。
Mysqlバックエンドをでっちあげてそっちに移行した
厳密さよりも速度を取っているんで、その点注意。あとZend_Cache::$availableBackendsにMysqlを追加しておく必要がある。
2006-07-20 [長年日記]
_ [1470.net][blogmap][OPML] フィード情報におかしな情報が混ざっているものがあります
blogmapのOPMLインポートのテストをしていたんだけど、なぜかその機能を使って追加したフィード情報に、おかしな情報が混ざっていることがあります。まだ原因は調査中(ライブラリのアップデートが影響しているかも?)ですが、妙な情報が登録されている(同一タイトルのフィードが重複していたり)フィードを見かけたら、教えていただければ修正します。
_ [1470.net][API] 内部APIいろいろ
日本で公開されているAPI一覧(下書き)とかからリンクされてたんで、どうせなら1470.netリニューアル版内部で使っているAPIも一応書いておこう。内部用なんでいつまで使えるかは未保証だけど。
個人で使う分には外部から適当に呼び出して使ってもいいけど、ばりばり使う場合は、タグ系API以外はどうせ元ネタを公開(位置情報+郵便番号データベース、鉄道路線+駅位置情報データベース)しているんで、自前でサーバー立てて使ってください。あと鉄道系DBをアップデートしてくれる人募集中。
都道府県一覧
- URL - http://1470.net/api/prefectures
- パラメータ - なし
- 戻り値
- 形式 - JSON(配列)
- 各要素 - キー「都道府県ID」、値「都道府県名」
市区町村一覧
- URL - http://1470.net/api/cities/[都道府県ID]
- パラメータ
- 都道府県ID - 都道府県一覧で取得したID
- 戻り値
- 形式 - JSON(配列)
- 各要素 - キー「市区町村ID」、値「市区町村名」
町域一覧
- URL - http://1470.net/api/cityareas/[市区町村ID]
- パラメータ
- 市区町村ID - 市区町村一覧で取得したID
- 戻り値
- 形式 - JSON(配列)
- 各要素 - キー「町域ID」、値「町域名」
郵便番号→住所推測
- URL - http://1470.net/api/zip/[郵便番号]
- パラメータ
- 郵便番号 - 半角数値7桁(ハイフンはなし)
- 戻り値
- 形式 - JSON(連想配列)
- 各要素
- address - 住所ID
- prefecture - 都道府県ID
- city - 市区町村ID
- cityarea - 町域ID
- title - 表示名
- 注意
- 郵便番号が市区町村レベルで定義されている場合でも、必ず町域レベルまで推測しようと試みるため、いわゆる郵便番号→住所変換データベースとは異なる結果になる
- 例
- 呼び出し: http://1470.net/api/zip/1500002
- 戻り値: {"address" : 59209, "prefecture" : 13, "city" : 615, "cityarea" : 59200, "title" : "東京都渋谷区渋谷一丁目"}
住所→位置情報変換
- URL - http://1470.net/api/location/[都道府県ID]/[市区町村ID]/[町域ID]
- パラメータ
- 都道府県ID
- 市区町村ID
- 町域ID
- 戻り値
- 形式 - JSON(連想配列)
- 各要素
- prefecture - 都道府県ID(エコー)
- city - 市区町村ID(エコー)
- cityarea - 町域ID(エコー)
- latitude - 緯度(世界測地系)
- longitude - 経度(世界測地系)
- 例
- 呼び出し: http://1470.net/api/location/13/615/59200
- 戻り値: {"prefectureId" : 13, "cityId" : 615, "cityareaId" : 59200, "latitude" : 35.66129, "longitude" : 139.70698}
位置情報から最寄りの住所推測
- URL - http://1470.net/api/nearAddress/[緯度]/[経度]
- パラメータ
- 経度 - 世界測地系。小数表現。
- 緯度 - 世界測地系・小数表現。
- 戻り値
- 形式 - JSON(連想配列)
- 各要素
- address - 住所ID
- prefecture - 都道府県ID
- city - 市区町村ID
- cityarea - 町域ID
- title - 住所表示名
- latitude - 住所を代表する緯度(世界測地系)
- longitude - 住所を代表する経度(世界測地系)
- zipcode - 住所で使われる郵便番号(推定)
- 例
- 呼び出し: http://1470.net/api/nearAddress/35.12355/139.23423
- 戻り値: {"address" : 67266, "prefecture" : 14, "city" : 712, "cityarea" : 67255, "title" : "神奈川県足柄下郡真鶴町真鶴", "latitude" : 35.15503, "longitude" : 139.14351, "zipcode" : 2590200}
鉄道路線一覧
- URL - http://1470.net/api/railways
- パラメータ - なし
- 戻り値
- 形式 - JSON(配列)
- 各要素 - キー「路線ID」、値「路線名」
- 注意
駅一覧
- URL - http://1470.net/api/stations/[路線ID]
- パラメータ
- 路線ID - 鉄道路線一覧で取得したID。
- 戻り値
- 形式 - JSON(配列)
- 各要素 - キー「駅ID」、値「駅表示名」
- 例
- 呼び出し: http://1470.net/api/stations/1
- 戻り値: {"8874" : "小沢", "8975" : "大麻", "8981" : "張碓", "8982" : "手稲", "8983" : "銭函", "8984" : "星置", "8985" : "稲穂", "8987" : "穂積公園", "8988" : "発寒中央", "8989" : "発寒", "8957" : "森林公園", "8956" : "厚別", "8875" : "銀山", "8876" : "然別", "8878" : "余市", "8880" : "小樽", "8881" : "塩谷", "8904" : "札幌", "8905" : "琴似", "8954" : "苗穂", "8955" : "白石", "9005" : "野幌", "9006" : "江別", "9124" : "奈井江", "9125" : "豊沼", "9128" : "滝川", "9131" : "江部乙", "9132" : "妹背牛", "9169" : "深川", "9171" : "納内", "9177" : "旭川", "9178" : "伊納", "9117" : "茶志内", "9027" : "峰延", "9008" : "豊幌", "9009" : "幌向", "9012" : "南小樽", "9013" : "小樽築港", "9014" : "朝里", "9019" : "上幌向", "9020" : "岩見沢", "9025" : "美唄", "9026" : "光珠内", "9179" : "近文", "8729" : "函館", "8777" : "駒ケ岳", "8778" : "赤井川", "8780" : "鹿部", "8781" : "本石倉", "8782" : "石谷", "8783" : "桂川", "8784" : "森", "8785" : "尾白内", "8786" : "東森", "8776" : "東山", "8775" : "姫川", "8730" : "五稜郭", "8763" : "結梗", "8764" : "七飯", "8765" : "大中山", "8766" : "渡島大野", "8767" : "大沼公園", "8768" : "大沼", "8769" : "仁山", "8770" : "池田園", "8787" : "掛", "8788" : "渡島砂原", "8812" : "長万部", "8819" : "蕨岱", "8866" : "黒松内", "8867" : "熱郛", "8868" : "目名", "8869" : "蘭越", "8870" : "昆布", "8871" : "ニセコ", "8872" : "比羅夫", "8811" : "二股", "8806" : "中ノ沢", "8789" : "渡島沼尻", "8791" : "野田生", "8792" : "石倉", "8793" : "落部", "8794" : "八雲", "8795" : "鷲ノ巣", "8800" : "黒岩", "8801" : "北豊津", "8805" : "国縫", "8873" : "倶知安"}
- 注意
駅位置情報
- URL - http://1470.net/api/station/[駅ID]
- パラメータ
- 駅ID - 駅一覧で取得したID。
- 戻り値
- 形式 - JSON(連想配列)
- 各要素
- id - 駅ID(エコー)
- name - 駅名
- latitude - 緯度(世界測地系)。小数表記。
- longitude - 経度(世界測地系)。小数表記。
- 例
- 呼び出し: http://1470.net/api/station/8874
- 戻り値: {"id" : 8874, "name" : "小沢", "latitude" : 42.97158, "longitude" : 140.67775}
- 注意
最寄り駅推測
- URL - http://1470.net/api/nearStation/[緯度]/[経度]
- パラメータ
- 緯度 - 世界測地系。小数表記。
- 経度 - 世界測地系。小数表記。
- 戻り値
- 形式 - JSON(連想配列)
- 各要素
- station - 駅ID
- latitude - 緯度。世界測地系。小数表記。
- longitude - 経度。世界測地系。小数表記。
- 例
- 呼び出し: http://1470.net/api/nearStation/35.66129/139.70698
- 戻り値: {"station" : 5581, "name" : "渋谷", "latitude" : 35.65767, "longitude" : 139.70342}
タグ推測(ユーザー、利用頻度、タグ名前方一致)
- 概要
- タグの利用頻度順に10件のタグを返す。
- ユーザー名を指定した場合、そのユーザーに関する情報。
- タグ名を指定した場合は、そのタグ名と前方一致でマッチするタグを返す。
- URL - http://1470.net/api/tag/list
- パラメータ(QUERY_STRING)
- userName - 1470.netユーザー名。省略可(省略時は全ユーザーが対象)
- tagName - タグ名(最初の部分だけでOK)。前方一致で検索する。省略可。
- 戻り値
- 形式 - JSON(連想配列)。resultノード以下。
- 各要素
- name - タグ名
- cnt - タグ利用回数
- 例
- 呼び出し: http://1470.net/api/tag/list?userName=ishinao&tagName=a
- 戻り値: {"result" : [{"name" : "AJAX", "cnt" : 26}, {"name" : "API", "cnt" : 11}, {"name" : "Amazon", "cnt" : 11}, {"name" : "Apache", "cnt" : 9}, {"name" : "ACCS", "cnt" : 6}, {"name" : "au", "cnt" : 5}, {"name" : "Apple", "cnt" : 4}, {"name" : "AV", "cnt" : 4}, {"name" : "AA", "cnt" : 2}, {"name" : "adsense", "cnt" : 2}]}
タグ推測(タグの相関)
- 概要
- あるタグと同時に使われることが多いタグ群を20件を返す。
- 元となるタグを複数渡すと、各タグごとの結果を加算し、多い順に20件返す。
- URL - http://1470.net/api/tag/related
- パラメータ(QUERY_STRING)
- query - タグ名。複数渡すときには半角スペース区切りで。
- 戻り値
- 形式 - JSON(連想配列)。resultノード以下。
- 各要素
- name - タグ名
- cnt - 利用回数
- 例
- 呼び出し - http://1470.net/api/tag/related?query=ajax%20php
- 戻り値 - {"result" : [{"name" : "javascript", "cnt" : 134}, {"name" : "JavaScript", "cnt" : 57}, {"name" : "Web", "cnt" : 29}, {"name" : "Programming", "cnt" : 24}, {"name" : "PHP", "cnt" : 22}, {"name" : "Internet", "cnt" : 19}, {"name" : "Ajax", "cnt" : 18}, {"name" : "computer", "cnt" : 18}, {"name" : "PEAR", "cnt" : 15}, {"name" : "フレームワーク", "cnt" : 15}, {"name" : "Ruby", "cnt" : 14}, {"name" : "Rails", "cnt" : 12}, {"name" : "セキュリティ", "cnt" : 12}, {"name" : "prog", "cnt" : 11}, {"name" : "Web2.0", "cnt" : 11}, {"name" : "Javascript", "cnt" : 10}, {"name" : "XML", "cnt" : 10}, {"name" : "Google", "cnt" : 10}, {"name" : "技術", "cnt" : 9}, {"name" : "JAVA", "cnt" : 8}]}
_ [1470.net][OMPL][blogmap] blogmapにOPMLでインポート
blogmapで情報を収集するフィードを、OPMLファイルを使って登録する機能を追加しました。
まだ挙動が怪しい部分があるんですが、その後のテストではどうしても再現できないんで、実稼働させてトラブルが出たら対処することにします。
一度のインポート処理に60秒間のタイムアウトを設定しているので、大量のフィードが記載されたOPMLファイルをインポートすると、いったんタイムアウトになることがあります。が、基本的に放っておく(あるいは明示的に「次に進みます」をクリックする)ことで、残りのフィードを取り込み続けますので。
2006-07-19 [長年日記]
_ [PHP][Zend Framework] 0.1.3+αから0.1.5への移行
1470.netで使っているZend Frameworkを、0.1.3をベースにいくつかの自前の修正とincubatorの取り込みを行ったバージョンから、0.1.5(というか最新のtrunk)に移行中。以下作業メモ。
- Zend_Db_Adapterのtype表記が、pdoMysql形式からPDO_MYSQL形式に変わったらしい。
- Zend_Service_Amazon周りのバグはいつまで経ってもなおんねーなー。報告はしてあるんだけど。それともjpでしか再現しないんだろうか? んなことないはずなんだけど。まあいいや。自分でなおしたバージョンを使おう。
- Zend_Db_Table::find()の挙動は相変わらず気に入らないんで、これも自分でなおしたバージョンに差し替え。っつーか、引数を配列にキャストして、要素が1個の場合はRowを返し、複数の場合はRowsetを返すって、すごい使いにくくないかなー。キーの配列を引数で渡すとき、たまたま要素数が1個になっちゃったときにRowで返される(受け取った側の扱いが変わる)のはすごく迷惑なんだけど。引数の型で戻り値の型を決めて欲しいなー。要望は出してあるんだけど。
- Zend_Http_Clientはincubatorバージョンにある、Cookieやchunkedエンコーディング、gzipエンコーディング等に対応したものに差し替え。俺が使う範囲ではほとんどバグがなくなった。
- Zend_Filter::isHostname()はまだ一文字要素があるホスト名(d.hatena.ne.jpとか)でtrueを返してくれないんで、その部分を差し替え。でもこれはバグトラックの方で進展があったんで、そのうち直ると思う。
- Zend_Json_Decoder::_eatWhitespace()は、相変わらずパイプを使った正規表現だとはてな認証APIのJSONがデコードできないんで、ここも自前で修正。
- そういやZend_Cacheはincubatorから標準添付に格上げされたんだね。incubatorの頃から使っているけど、memcachedバックエンドもちゃんと動いている。
- 本当だったらZend_Controller_RewriteRouterに移行したいところだけど、全然互換性がない自前のルーターで来ちゃってるんで、今更乗り換えられない。失敗したかなー。そういやincubatorの方にUrlヘルパー(Railsでいうurlfor。tokenからurlへの逆解決)が置いてあるね。
ってところまで直したところ、手元では一通り問題なく動いているんだけど、いつサーバーに適用しようかなー。
あぶないあぶない
Zend_FeedをRSS 1.0に対応させる修正を忘れていた。これをやらないと日本のRSSのかなりの数に対応できなくなってしまう。ちなみにこれは自前パッチじゃなくて、昔Zend Frameworkのtracに報告されていたパッチ。
アップデートした
本サーバーの方もアップデートした。特に問題なさそうに見えるけれども、何か怪しげな挙動があったら教えてください。
2006-07-18 [長年日記]
_ [1470.net][API][メモ情報取得API] メモ情報取得APIの仕様を変更しました
戻り値を直接ルートノードに返すのは今後の拡張性に問題があるため、結果を"result"というノード以下に返すようにしました。
今後は互換性のない仕様変更はないように気をつけますので。
_ [PHP][lighttpd][fastcgi] lighttpd+fastcgi+PHP 5って安定しない?の続報
TutorialLighttpdAndPHP - lighttpd - Tracの情報を参考に、"max-procs" => 2に設定してみたところ、連続稼働2、3日経っても以前みたいにCPUパワーを食い続けるプロセスが生まれたりはせず、安定して動いている。eacceleratorのsnapshotを入れている(ちなみにときどき特定のコード*1でエラーを吐くけど、基本的には高速化の恩恵の方が大きいんで、目をつぶって動かしている)んで「If you're using any php opcode cacher」には当てはまるんだけど、「unless you want to eat up so much memory」じゃなくて、CPUパワーだけを食っていたんだけどなー。
*1 array('' => '-')みたいな空文字列をキーにした配列とか
2006-07-17 [長年日記]
_ [1470.net][API] メモ情報取得API
主にメモデータバックアップ目的のためのメモ情報取得APIを用意しました。すみません。API仕様を変更してます。戻り値を直接ルートノードから返すのではなく、必ず"result"ノード下に収納することにしました。
リスト取得
- URL - http://1470.net/api/memo/list
- パラメータ(QUERY_STRING)
- userName - 1470.netユーザーID(省略可)。指定すると、そのユーザーのメモ情報のみが対象となる。
- updt - 更新日時(省略可)。指定するとその更新日時以降に更新されたメモのみが対象となる。
- リクエストメソッド - GET
- 戻り値
- データ形式 - JSON
- 例 {"info": {"totalCount": 1234}, "result": [{"id" : 998, "updt" : "2006-06-30 02:16:20"}, {"id" : 999, "updt" : "2006-06-30 02:16:21"}, ...]}
- info.totalCount - 該当した総項目数(2000を超えている場合、各項目として返るのは最初の2000件)
- result.* - 各項目
- id - メモID。メモにつけられたユニークなID。
- updt - メモの更新日時(JST)
- ソートオーダー
- updt asc。
- 制約
- 結果が2000件を超える場合は、最初の2000件のみを返す。その場合updtパラメータ指定などを使って、続きの情報を取得し直す必要がある。
メモ情報取得
- URL - http://1470.net/api/memo/[メモID]
- パラメータ - なし
- リクエストメソッド - GET
- 戻り値
- データ形式 - JSON
- 例 {"result": {"id" : 34553, "url" : "http://1470.net/user/ishinao/2006/07/01#m_34553", "title" : "集英社 ハチミツとクローバー 9 (9) 羽海野 チカ", "comment" : null, "eval" : null, "tags" : ["羽海野 チカ", "ハチクロ", "マンガ"], "groups" : {}, "uri" : {}, "mono" : [{"asin" : 4088653521, "uri" : "http://www.amazon.co.jp/exec/obidos/ASIN/4088653521/ref=nosim/ishinao-22", "title" : "集英社 ハチミツとクローバー 9 (9) 羽海野 チカ"}], "map" : {}, "event" : [{"name" : "集英社 ハチミツとクローバー 9 (9) 羽海野 チカ 発売日", "stdt" : "2006-07-14 00:00:00", "eddt" : null}], "todo" : null, "rgdt" : "2006-07-01 14:04:38", "updt" : "2006-07-16 20:55:51"}}
- 項目
- id - メモID
- userName - ユーザーID
- url - メモURL
- title - メモタイトル
- comment - コメント
- eval - 評価
- tags - タグ(配列)
- groups - グループ(配列)
- uri - メモに添付されたURI情報(配列)
- url - URL文字列。
- title - URIで示されたドキュメントのタイトル。
- mono - メモに添付されたMONO情報(配列)
- asin - ASINコード。
- url - Amazon個別商品ページURL。
- title - 商品情報(タイトル+著作者情報)。
- map - メモに添付された位置情報(配列)
- name - 位置情報名。
- latitude - 緯度。
- longitude - 経度。
- zoom - Google Maps APIにおけるズーム情報。
- event - メモに添付されたイベント情報(配列)
- name - イベント名。
- stdt - イベント開始日
- use_sttime - イベント開始日で時間要素も有効かどうか
- eddt - イベント終了日
- use_edtime - イベント終了日で時間要素も有効かどうか
- todo - メモに添付されたToDo情報
- name - 次に行うToDo名。
- tododt - その予定日。
- rgdt - メモ登録日
- updt - メモ更新日
バックアップクライアントサンプル実装
require_once 'Zend/Json.php';
$userName = 'ishinao';
$dataDir = '/tmp/backup';
$listUrl = 'http://1470.net/api/memo/list';
$itemUrl = 'http://1470.net/api/memo/';
$touchFile = $dataDir . '/touch';
$updt = filemtime($touchFile);
$rawListData = file_get_contents($listUrl . '?userName=' . urlencode($userName) . '&updt=' . urlencode(date('Y-m-d H:i:s', $updt)));
$decodedListData = Zend_Json::decode($rawListData);
$list = $decodedListData['result'];
foreach ($list as $row) {
$memoId = intval($row['id']);
if (!$memoId) {continue;}
$dataFile = $dataDir . '/' . $memoId . '.txt';
if (file_exists($dataFile) && (filemtime($dataFile) == strtotime($row['updt']))) {continue;}
$rawItemData = file_get_contents($itemUrl . $memoId);
$decodedItemData = Zend_Json::decode($rawItemData);
$item = $decodedItemData['result'];
if ($item['id'] != $memoId) {
throw new Exception('memo cannot read: ' . $memoId);
}
file_put_contents($dataFile, $rawItemData);
touch($dataFile, strtotime($row['updt']));
touch($touchFile, strtotime($row['updt']));
}
2006-07-16 [長年日記]
_ [1470.net][障害報告] 6時頃から8時半頃までサーバーが死んでました
今朝6時頃から8時半頃まで、フロントサーバーが刺さっていて、応答しない状態になっていました。
CRONDプロセスがやたらと増殖して、プロセス数を食いつぶして、shutdownすら効かない状態になっていた(ハードリセットした)んだけど、これはいったい何だったんだろう?
_ [1470.net][タグ入力][機能追加] タグ入力補助機能追加中
しばたさんの要望を中心に、タグ入力補助機能を追加していっています。
で、まずタグの「インクリメンタル・タグ補完」を追加しました。タグ欄に文字を入力すると、過去に自分が使用した、その文字から始まるタグを候補として表示されます。ただし、migemo風のローマ字入力→日本語推測→タグ補完まではできていません。これはmigemoを内部で使うよりも、自前で辞書を持った方がいいかもなー。
あと、同じURI、MONOを扱った他のメモに使われたタグを「おすすめ」として表示する機能もつけておきました。MONOの場合は、作者名なども「おすすめ」として表示します。
「関連語のsuggestion」(タグ自体の関連性をたどる)も難しくなさそうなんで、そのうち対応すると思います。
関連語のsuggestionもつけてみました
インターフェース的にはちょっと微妙だけど、使い物にはなるかな。
_ [1470.net][lighttpd][fastcgi][PHP] lighttpd+fastcgi+PHP 5って安定しない?
なんかしばらく動かしておくと、CPUパワーを消費し続けるPHPプロセスが生まれて、そいつらのせいでじわじわとload averageがあがっていく。lighttpdを再起動すると直るんだけど、場合によってはlighttpdを再起動しても上記のようなPHPプロセスが居座り続けて、強制的に殺さないといなくなってくれない。どこかに無限ループになるような処理があったりして、そいつがPHP/fastcgiプロセスとしてずっと動き続けてたりするんだろうか? ひとまず定期的にlighttpdは再起動しておくのが無難か?
2006-07-15 [長年日記]
_ [spam] 対応方法が思いつかないspam
そのページに書かれている文章から抜き取ったテキストの最後に1行(宣伝)URLを追加したツッコミspamがさっき来たんだけど、これって機械的な識別がえらく難しそうだな。日本語利用チェックとか、URL文字列割合チェックとか、その手の対応はすべて無効で、ほぼURL・ドメインベースのblacklistで対応するしか手はないんじゃなかろうか。
_ [1470.net][懸案事項][タグ入力] タグ入力支援機能の改善
リニューアル版1470.netのタグ入力支援機能を、使いにくいまま放置している。この辺は結局Ajaxを使わなければならず*1、Ajaxを使う場合はちゃんと設計してから作らないとぐだぐだになりがち*2なんで、隙間でちょっと機能追加するといった感じで作れない。
ひとまずタグ入力支援機能として、どういう機能があれば使いやすいのか自分の中でまとめ切れてないんで、具体的にどういう支援機能があればうれしいみたいなご意見募集中です。
_ [1470.net][API] データフォーマットはJSONでもいいでしょうか?
メモのバックアップ向けのAPIを作りかけている。インターフェースは基本RESTで行こうと思っているんだけど、データフォーマットをどうしようか悩み中。XMLが無難ではあるんだけど、やっぱりうざいなー。特にTSVとかCSVでも十分に表現できるようなデータを、わざわざXMLにするのがだるい。ただ、そういうときにTSVとかCSVとか使うってのも、扱うデータフォーマットの統一感とか、データが途中でぶち切れたとき対策とかの点でいまいちだ。で、今のところJSONにしちゃおうと思っていたりするんだけど、それだと困るって人はいますかねー。まあ最悪クライアント側のサンプル実装もこっちで作れば問題ないか。
_ funaki [zuzara.comの船木です。 こちらの方もリンクに加えさせていただきました。]