nkjmkzk.net

powered by Kazuki Nakajima

Archive for 6月, 2012

Chatterで訊く。世界中から答えを得る。多言語翻訳とQ&Aサイト連携で実現する世界の知恵袋

Chatterで「興味のあるフィード」とはどのようなものでしょうか?

第三者から発せられる情報は、受け取る側にとってその関心値は様々でしょう。
ただし、自身が「質問」したことに対する「回答」には誰しも高い関心を持つことは必然だと思います。

Chatterを導入している組織では、全社に対して、あるいは特定のグループに対して質問をおこない、意見を募るような使い方は極めてポピュラーだと言えるでしょう。通常こういったコミュニケーションは社内に閉じておこなわれることになります。社内だけで十分な回答を得られるケースもありますが、残念ながらレスポンスが得られないケースもあるでしょう。

そんなときに、該当する知見を社内外問わず収集することができれば、よりレスポンスを得られる可能性が高まります。

例えば、オープンなテクノロジーであるjQueryに関して使用方法を誰かに質問したいとします。組織によっては社内にエキスパートがいるかもしれませんが、オープンなソフトウェアなので社外のパブリックサイトに豊富な情報は蓄積されているであろうことは想像に難くありません。さらにjQueryは海外の開発者が立ち上げたソフトウェアなので日本ではなく、海外サイトの方が多くの情報を見つけることができるはずです。

日本人技術者の多くはある程度英語の読み書きは可能でしょう。しかし、英語サイトを積極的にブラウズしたい人は多くないのではないでしょうか。結果的に、英語サイトの情報を定常的に検索対象に入れる技術者は限られていると思います。

そこで、日本語でChatterに質問すれば社内外、国内外のエキスパートから回答が得られる。そんな仕組みが実現できれば、それは次世代のQ&Aシステムを構築できる、そんな可能性を感じませんか。

その仕組みに近しいデモアプリを作ってみました。ITの技術的な質問をChatterに日本語で投稿すると、類似するQ&Aを海外のQ&Aサイトから収集してくるというものです。

使い方は、まずChatterの標準画面で質問文を日本語で投稿します。そして、文末に「=>stackoverflow」と追加します。

そのままChatterに投稿されます。

ほどなくして画面をリロードすると、コメントに類似Q&Aが返信されてきます。

アーキテクチャーは下図のようになります。

質問文を翻訳する部分にGoogle Translate APIを使用し、海外のIT関連Q&AサイトとしてStackOverflowを使用しています。また、Heroku上に中間サーバとなるアプリを稼働させています。これは、Chatterフィードの書き込みからトリガーでHTTPコールアウトを発行する場合、非同期しか選択肢がないためです。非同期のコールアウトでは、コール先からレスポンスを取得することができません。したがって一旦Heroku上の中間サーバに処理を委任するという形をとっています。

それぞれの処理内容をみていきましょう。

  1. 標準のChatter画面で質問を日本語で投稿します。文末には「=>stackoverflow」と追加します。
  2. トリガーが起動し、フィードの本文中に=>stackoverflowの文字列を検出するとHeroku上で稼働している中間サーバに類似質問取得リクエストを非同期で送信します。
  3. リクエストを受け取った中間サーバはまずGoogle Translate APIを利用して質問文を英語に翻訳します。これは類似質問を検索するStackOverflowが英語サイトであるためです。
  4. 英語翻訳された質問文をStackOverflowの類似質問検索APIに送信し、類似質問を取得します。
  5. StackOverflowから返された類似質問を元のChatterフィードのコメントとして投稿します。

このデモアプリを「すごいQA for Chatter」としてパッケージングしてAppExchangeにアップロードしておきました。

https://login.salesforce.com/packaging/installPackage.apexp?p0=04tE0000000DKiB

このパッケージを既存のSalesforce組織にインストールすれば、その組織のChatterで上記のQ&Aをおこなうことができます。

*このパッケージはデモ用途専用です。各サーバ間の通信にはHTTPが用いられています。ご注意ください。

この仕組みは既存の類似Q&Aを取得するというものにとどまっています。これを一歩進めて、実際に英語翻訳したQ(質問)をStackOverflowに投稿し、A(回答) が投稿されればそれを検出して日本語翻訳し、Chatterコメントにフィードバックするような仕組みも十分可能でしょう。

現在、StackOverflow(厳密にはStackExchange API)で提供されているAPIは読み込み専用となっており、書き込み(質問投稿)のAPIは残念ながら用意されていません。これが提供されれば上記仕組みはすぐに実現可能でしょう。あるいはYahoo Answers等、書き込みAPIが用意されているサービスを検討するというのも一つの手だと思います。

このようなアイデアを発展させることで、あるサイトに登録されたユーザー、という枠にとらわれず、Socialなつながりで有機的な連鎖をおこすような次世代のQ&Aサイトが出来上がることを妄想している次第です。

最後にそれぞれの処理でキーとなるコードをAPIコールをメインにご紹介しておきます。

Chatterフィード書き込み時に発火し、必要に応じてQ&A処理を起動するトリガー

trigger feedItem_to_stackoverflow on FeedItem (after insert) {
    for (feedItem fi : Trigger.new) {
        if (fi.body.contains('=>stackoverflow')){
            string instanceUrl = URL.getSalesforceBaseUrl().toExternalForm();
            string sid = UserInfo.getSessionId();
            string fi_json = System.JSON.serialize(fi);
            chatter_stackoverflow.request_similar(sid, instanceUrl, fi_json);
        }
    }
}

Herokuの中間サーバに類似QA取得リクエストを送信するApexクラス

public with sharing class chatter_stackoverflow {
    @future(callout=true)
    public static void request_similar(string sid, string instanceUrl, string object_json){
        Http http_protocol = new Http();
        HttpRequest http_request = new HttpRequest();
        
        // Set the endpoint URL.
        instanceUrl = EncodingUtil.urlEncode(instanceUrl, 'UTF-8');
        sid = EncodingUtil.urlEncode(sid, 'UTF-8');
        String endpoint = 'http://dev.nkjmkzk.net/chatter/api.php?service=stackoverflow&sid=' + sid + '&instanceUrl=' + instanceUrl;
        http_request.setEndPoint(endpoint);
       
        // Set the HTTP verb to GET.
        http_request.setMethod('POST');
        
        // Set body
        http_request.setBody(object_json);
        
        // set callout timeout to 60sec(max)
        http_request.setTimeout(60000);
       
        // Send the HTTP request and get the response.
        // The response is in JSON format.
        if (!Test.isRunningTest()){
        	http_protocol.send(http_request);
        }
    }
}

Heroku(php)の中間サーバからGoogle Translate APIを呼び出して英語翻訳を取得するREST APIのURL

https://www.googleapis.com/language/translate/v2?format=text&key=あなたのAPI KEY&q=英語翻訳する質問文&target=en

Heroku(php)の中間サーバからStackExchange APIを呼び出して類似QAを取得するREST APIのURL

http://api.stackexchange.com/2.0/similar?order=desc&sort=relevance&title=英語翻訳した質問文&site=stackoverflow

Heroku(php)の中間サーバからChatter REST APIを呼び出して類似QAをコメントにフィードバックするREST APIのURL

https://インスタンス.salesforce.com/services/data/v25.0/chatter/feed-items/親フィードのID/comments?text=類似QAのタイトル

without comments

Written by 中嶋 一樹

6月 29th, 2012 at 2:44 pm

Posted in Uncategorized

Tagged with ,

膨大な量のChatterフィードから重要情報だけをピックアップする「すごいChatter分析」

コミュニケーションの中心をメールからChatterに移行すると何が変わるのでしょうか?

僕が考える答えの一つは「コミュニケーションがオープンになる」です。

メールは基本的に情報が入ってくるのを待つアプリケーションであり、一方、Chatterは情報を自発的に見にいくことができるアプリケーションです。この違いは大きい。

例えば経営者が会社で何が起こっているか知りたい場合、多くの組織では部門長からのレポートを待つほかありません。日々おこなわれているメールでのコミュニケーションはToに入っていない人には完全にクローズドになります。

一方、各プロジェクトや部門内でのコミュニケーションをChatterでおこなっている場合(そしてそれが公開グループでおこなわれている場合)、経営者は現場での出来事やコミュニケーションを部門長のレポートを介さずアクセスすることができるようになります。社内の動きをより正確に把握したいアグレッシブな経営者には重要な情報です。

ただ、会社規模が大きくなるにつれ、グループ(部門やプロジェクト)の数は増え、やりとりされているフィード数も爆発的に増加します。TwitterでもFollow数は100を超えると、閲覧方法を工夫しないと情報を追いかけることが難しくなってきます。

どのようにすれば情報の海の中から価値のある情報をクイックにピックアップできるでしょうか?

僕はひとつのアイデアとして、「キーフレーズ抽出」を提案します。

大量の文章に目を通すのは特殊な速読技術を擁さない限り、それなりの時間を根気を必要とします。もし、それらが限られた数のキーワード・キーフレーズのみに絞られて表示されれば、ダッシュボードのように一目で重要なトピックを認識し、そのトピックに関するコミュニケーションだけドリルダウンすることができるはずです。

経営者の例で言えば、各部門やプロジェクト毎に「本日のキーフレーズ」がまとまっていれば、朝の限られた10分というような時間でも会社の状態を掴むことができるかもしれません。

そのキーフレーズ抽出をどのように実現していくかを考えていきます。

日本語はそもそも単語が規則的なデリミターで区切られておらず、文章を構成単位(形態素)に分解し単語を抜き出すのが難しい言語です。その中で、キーフレーズを抽出する簡単なアルゴリズムを考える場合、まず文章の形態素を認識し、その中から固有名詞だけを抽出し、さらにその固有名詞の出現回数をもって重要度をスコアリングするようなアルゴリズムが一つ考えられます。

ただし固有名詞というくくりが必ずしもトピックのすべてとは限りませんし、出現回数だけで「キー(重要)」かどうか判断するのはやや乱暴です。

しかし、世の中には便利なサービスがあるもので、Yahoo Japanさんが日本語文章を送信するだけでそのキーフレーズを抽出&スコアリングして結果を返してくれるキーフレーズ抽出APIを提供してくれています。このサービスは無償で利用することができます。これを使ってみましょう。

一つの構成として、アーキテクチャーは下図のように設計しました。

  1. 最終的なダッシュボードを提供する外部Webサーバにアクセス
  2. Chatterから自分が参加しているグループ(今回は部門またはプロジェクトが設定されていることを想定)のリストと、それぞれのフィード情報を取得
  3. フィード情報をグループ毎に一つのテキストに結合し、Yahooキーフレーズ抽出APIに送信してキーフレーズを取得
  4. Yahooから返してくれるキーフレーズを、セットで提供されるスコアに基づいてフィルタリング、ソートし、ダッシュボードを生成

ダッシュボードを生成するWebサーバにHerokuを用いているのは、もしYahooからの応答時間がForce.comのコールアウトタイムアウトしきい値を超えた場合でもエラーを回避するため、というのが一つの理由です。こういう類いの処理は時間を要することが想定されるので、安全を見越して、ということです。

外部サービスと連携するときは、Force.comから直接のアクセスに固執すると今回のようにコールアウトの待ち時間や、同期でコールアウトが発行できる場合、できない場合があり、制限に抵触するパターンにしばしば遭遇します。中間サーバをひとつ念頭に置いておくと多くのFoce.comの制約を回避でき、よりアプリケーションの幅が広がる可能性があるではないかと思います。

実際のアプリケーションがこちらです。

すごいChatter分析

もし現在Chatterをご利用の方は実際にOAuthで認証いただくことでご自身の組織のChatterフィードをグループ毎に分析することができます。
*本アプリケーションはデモ用途専用です。HerokuからYahoo APIへの通信はHTTPでおこなわれています。ご注意ください。

画面は大きく分けてキーワードとHot Feedの2つで構成されています。

キーワードの方が今回ご紹介した仕組みで動作しており、各キーワードをクリックするとそのキーワードが出現したフィードをドリルダウンして追うことができます。

Hot Feedはコメント数とLike数にしきい値を設定し、一定以上の話題をあつめたフィードを表示するという仕組みです。

最後に、このアーキテクチャのそれぞれの処理でキーとなるAPI呼び出しをご紹介しておきます。今回のアイデアが皆様がChatterを活用したアプリを開発する上で何らかのヒントになれば幸いです。

まずHeroku (php)からChatterのAPIにアクセスし、グループ情報をフィード情報を取得する部分のコードです。

    // メンバーとなっているグループ一覧を取得
    public function get_my_chatter_groups(){
        $url = $this->instance_url . "/services/data/" . $this->api_version . "/chatter/users/me/groups";
        $this->logger->logger("URL : " . $url, __CLASS__, __FUNCTION__);
        $response = $this->callout_for_get($this->access_token, $url);
        if ($this->logger->error){
            $this->logger->set_error("Failed to get my chatter groups.", __CLASS__, __FUNCTION__);
            return(false);
        }
        return($response['groups']);
    }

    // News Feedからフィード情報を取得
    public function get_all_feeds(){
        $url = $this->instance_url . "/services/data/" . $this->api_version . "/chatter/feeds/news/me/feed-items";
        $this->logger->logger("URL : " . $url, __CLASS__, __FUNCTION__);
        $response = $this->callout_for_get($this->access_token, $url);
        if ($this->logger->error){
            $this->logger->set_error("Failed to get all feeds by group.", __CLASS__, __FUNCTION__);
            return(false);
        }
        return($response['items']);
    }

次にHeroku (php)からYahooのAPIにアクセスし、キーフレーズを抽出する部分のコードです。

    // Yahoo APIにフィード情報を送信し、キーフレーズを抽出
    public function get_keywords($sentence, $min_score){
        $api_key = urlencode($this->api_key);
        $sentence = $this->strip_mention($sentence);
        $sentence = urlencode($sentence);
        $url = "http://jlp.yahooapis.jp/KeyphraseService/V1/extract?output=json&appid=" . $api_key;
        $response = $this->callout_for_post($url, $sentence);

        $offset = 0;
        $keywords = array();
        foreach($response as $k => $v){
            if ($v < $min_score){
                continue;
            }
            $keywords[$offset]['value'] = $k;
            $keywords[$offset]['score'] = $v;
            $offset++;
        }
        return($keywords);
    }

without comments

Written by 中嶋 一樹

6月 28th, 2012 at 3:50 pm

Posted in Uncategorized

Tagged with , ,