Lambda Custom RuntimesとLayersの仕組みを使ってPerlとMeCabで形態素解析をする

LambdaでPerlが実行できる環境と、MeCabを利用してリクエストが来た文章の形態素解析を行う関数を実装しました。
2018.12.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

事業開発部の野村です。本記事はAWS Lambda Custom Runtimes芸人 Advent Calendar 2018の11日目の記事です。

はじめに

先日のre:Invent 2018で発表したCustom Runtimes

【アップデート】 もう言語で悩まない!AWS LambdaでCustom Runtimeが利用できるようになりました! #reinvent

社内でも早速アドベントカレンダーができるなどお祭り状態でしたので便乗してみました。

私はLambdaでPerlが実行できる環境と、MeCabを利用してリクエストが来た文章の形態素解析を行う関数の実装にチャレンジしました。 AWS Lambda Layersも使ってます。

まだ開発途中ではあるのですが備忘録も兼ねて残しておきます。

今回開発するもの

  • LambdaのLayerにPerlとMeCabの実行基盤を配置する
  • 以下のリクエストにあるテキストを元に形態素解析を実施し、解析結果を返す関数をPerlで実装する

リクエスト

{
  "text": "形態素解析のテスト"
}

レスポンス

{
    "result" : [
      {
        "surface" : "形態素",
        "feature" : "名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ",
        "cost" : 5338
      },
      {
        "feature" : "名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ",
        "cost" : 9241,
        "surface" : "解析"
      },
      {
        "feature" : "助詞,連体化,*,*,*,*,の,ノ,ノ",
        "cost" : 10265,
        "surface" : "の"
      },
      {
        "cost" : 11987,
        "feature" : "名詞,サ変接続,*,*,*,*,テスト,テスト,テスト",
        "surface" : "テスト"
      },
      {
        "cost" : 11251,
        "feature" : "BOS/EOS,*,*,*,*,*,*,*,*",
        "surface" : "undef"
      }
    ]
}

前提

開発環境で以下を利用しています。

  • macOS Mojave 10.14.1
  • Docker version 18.09.0, build 4d60db4
  • aws-cli 1.16.72

ソース

https://github.com/K1-Style/lambda-perl-mecab を使います。

$ git clone https://github.com/K1-Style/lambda-perl-mecab.git
$ cd lambda-perl-mecab

PerlとMeCab実行基盤を作るためのDockerイメージを用意

Dockerを使って、PerlとMeCabの実行基盤を作ります。Lambdaの実行環境と合わせるため lambci/lambda をベースにしています。

$ docker run -it --name lambda-perl-mecab-container -v $(pwd):/var/task lambci/lambda:build ./install.sh

Perlで利用するMeCab用のライブラリText::MeCabのインストール時にmecab-configのファイルパスや利用する文字コードの入力待ちになるタイミングがあります。それぞれ以下を入力します。

Path to mecab config? /opt/bin/mecab-config
Encoding of your mecab dictionary? (shift_jis, euc-jp, utf-8) [euc-jp] utf-8

コンテナが出来たら、Lambda Layersのビルド作業に今後使うのでDockerイメージを作っておきます。

$ docker commit lambda-perl-mecab-container lambda-perl-mecab

イメージが出来たら、作ったコンテナは不要なので削除しても問題ありません。

$ docker rm lambda-perl-mecab-container

Lambda Layers用のzipアーカイブを作る

先程作ったDockerイメージを使ってLambda Layers向けのzipアーカイブを作ります。

$ docker run --rm -it -v $(pwd):/var/task lambda-perl-mecab ./build-layer.sh

出来上がったlambda-perl-mecab.zipをLayerとして登録します。

$ aws --region $REGION --profile $PROFILE lambda publish-layer-version \
  --layer-name perl-mecab-layer \
  --zip-file fileb://lambda-perl-mecab.zip

Lambda関数を用意

以下のhandler.plを用意し、こちらもzipアーカイブ化します。

use utf8;
use warnings;
use strict;
use Text::MeCab;
use Data::Dumper;

sub function {
    my ($payload) = @_;
    my $mecab = Text::MeCab->new();
    my @array;
    for (my $node = $mecab->parse($payload->{text}); $node; $node = $node->next) {
        my $word = {
        	surface => $node->surface,
        	feature => $node->feature,
        	cost => $node->cost,
        };
        push(@array, $word);
    }

    my $result = {
        result => \@array,
    };

    warn Dumper($result);

    return $result;
}

1;
$ zip handler.zip handler.pl

Lambda関数として登録します。

$ aws --region $REGION --profile $PROFILE lambda create-function \
  --function-name "lambda-perl-mecab-function" \
  --zip-file "fileb://handler.zip" \
  --handler "handler.function" \
  --runtime provided \
  --role arn:aws:iam::xxxxxxxxxxxx:role/service-role/lambda-custom-runtime-perl-role \
  --layers arn:aws:lambda:xxxxxxxx:xxxxxxxxxxxx:layer:perl-mecab-layer:1
  • --roleに指定するIAMロールは予め作成済みとします。
  • --layersに先程作成したLayerのARNを入力します。

テスト

以下で実行確認します。

$ aws --region $REGION --profile $PROFILE lambda invoke \
  --function-name "lambda-perl-mecab-function" \
  --payload '{"text":"形態素解析のテスト"}' \
  output.json

output.jsonにレスポンスとなるjsonが入りますが、現状日本語が文字化けしてます… ここは引き続き調査します。

2018-12-21 追記

bootstrapで返すjsonのエンコード処理をちょっと変えたら文字化け直りました。githubのコードも修正

参考文献

今回の検証にあたり大いに参考にさせてもらいました。

さいごに

Lambda LayersやCustom Runtimesの仕組みを今回の実装や参考サイトを通して理解が深まりました。Lambdaでできることが随分と広がりましたね。

駆け足でざっと作ってしまいましたが、文字化けの件も含めもう少し検証して再度展開しようと思います。

それでは本日はこれにて。