jsonengineの全文検索機能をローカル開発環境でも動くようにした

jsonengineのサンプルであるbbs.htmlはそのままだとローカル開発環境で動かした場合に「java.lang.IllegalArgumentException: Invalid uri」が発生し更新できない。例外発生の原因はyahoo apiサービスである日本語形態素解析を利用しているのが原因。問い合わせにGETメソッドを使用しているのだがパラメーター文字列の解釈で例外が発生するようだ。本番環境のappspot.comへデプロイすれば動作するが動作確認の為に毎回デプロイすると非常に開発のリズムが悪い。

全文検索機能は開発時にも是非使いたい。そうじゃないと魅力が半減してしまい結局サーバーサイドへ手を出す羽目になってしまう。

何とかならないかと詳しく調べたところyahoo apiはPOSTメソッドの問い合わせにも対応していたのでそれでテストしてみた。結果は問題なく意図通り動作した。具体的なソースを記録として残しておく。修正箇所はJEUtils.javahttp://code.google.com/intl/ja/appengine/docs/java/urlfetch/usingjavanet.html#Using_HttpURLConnection を参考にした。

JEUtils.java

public class JEUtils {

〜〜〜他のメソッド等は省略

    /**
     * Extract terms from the text by using Yahoo's term extraction web service.
     * 
     * @param text
     * @return a Set of extracted terms
     */
    public Set<String> extractTerms(String text) {
        final Set<String> propValues = new HashSet<String>();
//      final String result = callURL(YAHOO_PARSE_JA + text);
        final String result = callYahooAPI(text);
        final Matcher m = termPattern.matcher(result);
        while (m.find()) {
            propValues.add(m.group(2));
        }
        return propValues;
    }

    public static final String YAHOO_PROTOCOL_JA =
        "http://";

    public static final String YAHOO_HOST_JA =
        "jlp.yahooapis.jp";

    public static final String YAHOO_MASERVICE_JA =
        "/MAService/V1/parse";

	//ここは各自のappidを使った方がいいかも
    public static final String YAHOO_APPID_JA_ =
        "appid=" 
            + "QZWK7SGxg67FGZpOHgk2rMkwNL5EMOXhnNXqEDKpk32FwzA8PFcgFirTdE6zXJDnKtnp";

    public static final String YAHOO_RESPONSE_JA = 
        "response=" 
            + "surface,reading";

    public static final String YAHOO_FILTER_JA = 
        "filter=" 
            + "1|3|5|6|7|8|9|10";

    public static final String YAHOO_SENTENCE_JA = 
        "sentence=";

    public String callYahooAPI(String text) {
        final StringBuilder sb = new StringBuilder();
        try {
            URL url = new URL(YAHOO_PROTOCOL_JA + YAHOO_HOST_JA + YAHOO_MASERVICE_JA);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setRequestMethod("POST");

            OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
            String param =  YAHOO_FILTER_JA
                    + "&" + YAHOO_RESPONSE_JA
                    + "&" + YAHOO_APPID_JA_
                    + "&" + YAHOO_SENTENCE_JA
                    + URLEncoder.encode(text, "UTF-8");
            writer.write(param);
            writer.close();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                BufferedReader reader =
                    new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
                String line;
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
                reader.close();
            } else {
                // output error log
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
        
    }

}

JEUtilsTest.java

public class JEUtilsTest extends AppEngineTestCase {

    @Test
    public void testCallYahooAPI() {
        final String result = (new JEUtils()).callYahooAPI("本日は晴天なり");
        assertNotNull(result);
        final List<String> values = this.extractTerms(result);
        assertEquals("本日", values.get(0));
        assertEquals("ほんじつ", values.get(1));
        assertEquals("晴天", values.get(2));
        assertEquals("せいてん", values.get(3));
    }

    private static Pattern termPattern = Pattern
        .compile("<(surface|reading)>([^<]*)</(surface|reading)>");

    private List<String> extractTerms(String result) {
        final List<String> list = new ArrayList<String>();
        final Matcher m = termPattern.matcher(result);
        while (m.find()) {
            list.add(m.group(2));
        }
        return list;
    }

}