2016/12/16

BlobstoreUploadHandlerの文字化け問題の解決方法

Google App Engine Python2.7環境で、blobstore_handlers.BlobstoreUploadHandlerを使って、ファイルアップロードする際、日本語のリクエストパラメータが文字化けする問題に長年悩まされていた。

「文字化け」といっても、マルチバイト文字はBase64にエンコードされて送信される、という謎仕様。さらに、文字の組み合わせによっては Base64ではなく、Quoted-printable にエンコードされたりと、意味がわからない。。。

そんなわけで、ファイルとテキストは、別のリクエストに分けたりと、クライアント側で対処していた。

先日、この問題をGCPのサポートに問い合わせた結果、あっさりと対応方法を教えてくれた。

app.yamlに以下を追加すれば良いだけ。

libraries:
- name: webob
  version: "1.2.3"

なんと、WebObのバグだったようだ。
http://docs.webob.org/en/stable/changes.html#id25

GAEのPython2.7環境では、webobの1.1.1(かなり古い)がデフォルトらしく、1.2.3で解決されたこのbugfixのため、この対応で回避できる。という事らしい。

といっても、1.2.3もかなり前のバージョンなので、もっと上位のバージョンしても問題なさそうだけど、今回はこのバージョンで様子見で。。。

そろそろ、Goに移行しようかなぁ。。。

2015/12/11

DatastoreとSerach APIを連携させる


Datastoreでは、複数のフィールドに対して不等式検索(!=や>など)やソートを行う場合、事前にIndexを構築しておく必要がある。しかも全ての検索条件の組み合わせごとにIndexが必要になるので、バックオフィス機能にありがちな複雑な条件での検索を行いたい場合、多くのIndexが必要だ。

2014/10/03

Google Compute Engineが10%OFFに


嬉しいニュースですね。6ヶ月前の発表どおり、ムーアの法則に従った結果の値下げのようです。

ハードの値段が下がった結果とはいえ、自社でコストカットできた結果を、こんなに早いタイミングでユーザーに還元する企業ってそんなに無いのではないでしょうか。

この調子だと、来年の春にはまた嬉しいニュースが聞けるかもしれませんね。その時はGoogle App Engineも値下げてくれると嬉しいなぁ。

あとは、良いサービス作るだけだ。。。(2回目)

2014/09/25

HTTPロードバランサが公開プレビューに


限定プレビュー版だったGoogle Cloud Platform のロードバランサが誰でも使える公開プレビュー版になったようです。

このロードバランサの凄いところは、Google検索やGmail、Youtube等の主要Googleサービスと同じインフラに乗っかっているので、圧倒的なパフォーマンスを低価格(約1800円/月)で提供できているという事。また、ロードバランサに対しての監視や設定もRESTful APIが用意されているので、アプリケーション側から動的&柔軟な対応もできる。

リリースされれば、今後Google Cloud Platformの目玉のひとつになるかもしれない。
それにしても、インフラのコストはどんどん安くなるなぁ・・・あとはこのロードバランサに不満を持つほどのWebサービスを作るだけだ。

以下、関連記事まとめ。

Googleの中の人による解説: GoogleのHTTPロードバランサーの破壊力があり過ぎる #gcpja
国内メディア記事: Google Cloud PlatformのHTTPロードバランサーがオープンプレビューに。ウォームアップなしで100万リクエスト/秒に対応する性能、1つのグローバルIPで複数リージョンに分配

2014/09/24

Google Custom Search を使って評価の低い(高い)レビューを検索する

前回記事に続き、Google Custom Search API を使って、もっと詳細に条件を指定する方法をメモ。

Google Custom Searchの公式ドキュメントによると、構造化データの情報を指定して、さらにフィルタリングができるみたい。

To filter by attribute, add a more:pagemap:TYPE-NAME:VALUE operator to a search query.

とあるので、検索キーワードに、more:pagemap:属性名:属性値を追加すればOK。

APIの戻り値を見てみると、価格.comのレビューの評価数の属性値は、review-ratingstarsでとれるので、例えば、評価数3のレビューのみ取得したい場合は、検索キーワードmore:pagemap:review-ratingstars:3.0とすることで、フィルタリングすることができる。また、値をカンマで区切る事でOR条件も指定できる。例えば、評価4と5も含めたい場合はmore:pagemap:review-ratingstars:3.0,4.0,5.0と書ける。前回のフォームに、評価数を指定するプルダウンを設置してみた。ソースはこんな感じ。

入力フォーム

<form class="form-horizontal" role="form" action="search" method="post">
    <div class="form-group">
      <label class="col-sm-2 control-label" for="keyword">キーワード</label>
      <div class="col-sm-10">
        <input type="text" id="keyword" name="keyword" class="form-control" >
      </div>
    </div>
    <div class="form-group">
      <label for="stars" class="col-sm-2 control-label">評価</label>
      <div class="col-sm-10">
        <select class="form-control" id="stars" name="stars">
          <option value="">指定しない</option>
          <option value="1.0">★☆☆☆☆</option>
          <option value="2.0">★★☆☆☆</option>
          <option value="3.0">★★★☆☆</option>
          <option value="4.0">★★★★☆</option>
          <option value="5.0">★★★★★</option>
        </select>
      </div>
    </div>
    <button type="submit" class="btn btn-primary">検索</button>
</form>

リクエストハンドラ 

#!-*- coding:utf-8 -*-
#!/usr/bin/env python
import json
import logging
import urllib
from google.appengine.api import urlfetch
from lib.controller import *

class Top(Controller):
    def get(self):
        self.draw_template('front/cse/top.html')

class Search(Controller):
    def post(self):
        # キーワードを得る
        keyword = self.request.get('keyword')
        # 評価が指定されていればキーワードに追加
        stars = self.request.get('stars')
        if stars:
            keyword += ' ' + 'more:pagemap:review-ratingstars:%s' % stars
        # urlエンコード
        keyword = urllib.quote(keyword.encode('utf-8'))
        # リクエストパラメータ組み立て
        url = 'https://www.googleapis.com/customsearch/v1'
        url += '?key=%s' % 'YOUR_API_KEY'
        url += '&cx=%s' % '000122034385005128488:etmrnaufuww'
        url += '&q=%s' % keyword
        # 検索
        result = urlfetch.fetch(url)
        logging.info(url)
        items = list()
        if not 200 <= result.status_code <= 299:
            # エラー
            logging.error('google custom search error: %s' % str(result.status_code))
            logging.error(result.content)
        else:
            # 結果を得る
            content_dict = json.loads(result.content)
            items = content_dict.get('items', list())
        self.set_template_value('items', items)
        self.draw_template('front/cse/search.html')

url_map = [
    ('/cse/top', Top),
    ('/cse/search', Search),
]
application = webapp.WSGIApplication(url_map, debug=True)

ちなみにAPI越しじゃなくても、Custom Search の追加キーワードでも指定できるみたい。ただ、この属性名がreview-ratingstarsとなっているのが、Google独自の命名なのか、構造化ルールでの命名なのかが不明。。。このあたりはもう少し調べてみます。

Google App Engine SDK Version 1.9.12 リリース

Google App Engine SDK のバージョン 1.9.12 がダウンロード可能になっています。

が、、、リリースノートは更新されていない様子。更新されたら追記します。

【追記】
リリースノート更新されてました。pythonは以下の2点が更新されたようです。

  • libxsltライブラリのバージョンがv1.1.22からv1.1.28に。
  • NDBでクエリを実行した時に「AugmentedQuery’ object has no attribute ‘filter_predicate’」というエラーが発生する問題を対応。

Python版については、ここしばらくマイナーアップデートが続いていますね。そろそろアジアリージョン来て欲しい!

2014/09/16

Google App Engine Version 1.9.11 リリース(Python)

4日前ですが、Google App Engine SDK Version 1.9.11 がリリースされています。今後はリリース情報も掲載していく予定です。とりあえずPythonのみ。

Python版では、Search API の日付順の結果が正しく返却されるようになったようです。

Google App Engine Python and PHP SDK Release Notes