本記事はAWS LambdaとServerless Advent Calendar 2021、21日目の記事です。
ちょっと前に業務でとあるアイテムのサジェスト系のAPIのプロトタイプを作る時にMecabを使おうと思ったのですが、ちょちょいとはできずに一旦含めないことにした事があります。
でも結局の所、必要になりそうなのでやっておこう。
似たようなネタはけっこうあって、何番煎じなん?ってトコはあるのですが、samかつコンテナでやる例は見つからなかったのでセーフとします。
# 何をやるのか
実際にはもうちょっと複雑なのですが、 今回は名称のDBがあって、それに対して名詞の単語のみでクエリを実行する
というシンプルなシナリオとします。
例えば、 **「伝説の勇者が使ったとされるひのきのぼう」**で検索されたとします。
伝説 名詞,一般,*,*,*,*,伝説,デンセツ,デンセツ
の 助詞,連体化,*,*,*,*,の,ノ,ノ
勇者 名詞,一般,*,*,*,*,勇者,ユウシャ,ユーシャ
が 助詞,格助詞,一般,*,*,*,が,ガ,ガ
使っ 動詞,自立,*,*,五段・ワ行促音便,連用タ接続,使う,ツカッ,ツカッ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
と 助詞,格助詞,引用,*,*,*,と,ト,ト
さ 動詞,自立,*,*,サ変・スル,未然レル接続,する,サ,サ
れる 動詞,接尾,*,*,一段,基本形,れる,レル,レル
ひのき 名詞,一般,*,*,*,*,ひのき,ヒノキ,ヒノキ
の 助詞,連体化,*,*,*,*,の,ノ,ノ
ぼう 名詞,一般,*,*,*,*,ぼう,ボウ,ボウ
名詞としては、伝説、勇者、ひのき、ぼうが抜き出せました。
今回はmecabという形態素解析エンジンをLambda上で用いて名詞に分解する、ということがやりたい、という話となります。本当はLambda Layerでやってみたかったのですが、250MBの制限があったりとか、Layer with コンテナができなかったりとかで諦めました。
mecabとは
オープンソースの形態素解析エンジンです。文章を食わせると、名詞や動詞など単語に分解してくれます。分かち書きとデータベース検索を合わせて使う時になんかにも便利です。
MeCabはオープンソースの形態素解析エンジンで、奈良先端科学技術大学院大学出身、現GoogleソフトウェアエンジニアでGoogle 日本語入力開発者の一人である工藤拓[1][2]によって開発されている。名称は開発者の好物「和布蕪(めかぶ)」から取られた。
mecab-python3
pythonでmecabを使う時にはこのモジュールを使います。
https://pypi.org/project/mecab-python3/
が、mecabを使うにはこれだけでは足りず、別途mecabのライブラリ(バイナリ)や辞書をインストールしなければいけません。
requirements.txtを用意するだけでは足りず、モジュールごとアップロードするだけでも足りません。
これはlambdaをコンテナイメージとして構築する事にし、イメージ構築時にインストールする事にします。
NEologd
NEologd とはmecabで使用できる、どデカい辞書です。
比較的新しいワードにも対応しているらしく、新しいデータを対象とするサービスでは必要になりそうです。
必要なものだけに絞ったりもできるらしですが、今回は深く考えずに突っ込んでいます。
Lambdaの作成
hello worldを一回作る(テンプレ)
まず、前提としてsam cliのインストールが必要です。まだの方はググってawsへのdocumentへたどり着いていただければと思います。
※古いsam cliをお使いの方はDocker imageに対応しているversionにupgradeして下さい
で、最初はsam initでテンプレから作っておきます
$ sam init --name lambda-python-mecab-sam-example
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
What package type would you like to use?
1 - Zip (artifact is a zip uploaded to S3)
2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2
Which base image would you like to use?
1 - amazon/nodejs14.x-base
2 - amazon/nodejs12.x-base
3 - amazon/nodejs10.x-base
4 - amazon/python3.9-base
5 - amazon/python3.8-base
6 - amazon/python3.7-base
7 - amazon/python3.6-base
8 - amazon/python2.7-base
9 - amazon/ruby2.7-base
10 - amazon/ruby2.5-base
11 - amazon/go1.x-base
12 - amazon/java11-base
13 - amazon/java8.al2-base
14 - amazon/java8-base
15 - amazon/dotnet5.0-base
16 - amazon/dotnetcore3.1-base
17 - amazon/dotnetcore2.1-base
Base image: 4
...
(続く)
一番のポイントは What package type would you like to use? で 2
と答えることです。
(続き)
Cloning from https://github.com/aws/aws-sam-cli-app-templates
AWS quick start application templates:
1 - Hello World Lambda Image Example
2 - PyTorch Machine Learning Inference API
3 - Scikit-learn Machine Learning Inference API
4 - Tensorflow Machine Learning Inference API
5 - XGBoost Machine Learning Inference API
Template selection: 1
-----------------------
Generating application:
-----------------------
Name: lambda-python-mecab-sam-example
Base Image: amazon/python3.9-base
Architectures: x86_64
Dependency Manager: pip
Output Directory: .
Next application steps can be found in the README file at ./lambda-python-mecab-sam-example/README.md
Commands you can use next
=========================
[*] Create pipeline: cd lambda-python-mecab-sam-example && sam pipeline init --bootstrap
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
その他にはpythonの3.9を選んだりしつつ、とりあえずHello Worldのテンプレを選びます
上記を終えるとこんな感じの構成になってるはずです。
.
├── README.md
├── __init__.py
├── events
│ └── event.json
├── hello_world
│ ├── Dockerfile
│ ├── __init__.py
│ ├── app.py
│ └── requirements.txt
├── template.yaml
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_handler.py
ここで編集する必要があるのは3つ
- Dockerfile
- app.py
- requirements.txt
ですね。
Dockerfileではmecabやライブラリをインストールします。
app.pyではMeCabをimportしたプログラムを動かします
requirements.txtではmecab-python3を含むライブラリを管理します。
Dockerfileの作成
FROM public.ecr.aws/lambda/python:3.9
RUN yum install -y file tar gzip unzip gcc make swig gcc-c++ git
RUN curl -L 'https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE' -o mecab-0.996.tar.gz \
&& tar zvxf mecab-0.996.tar.gz
RUN (cd mecab-0.996 && ./configure --prefix=/var/task --enable-utf8-only && make && make install)
RUN curl -L "https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7MWVlSDBCSXZMTXM" -o mecab-ipadic-2.7.0-20070801.tar.gz \
&& tar -zxvf mecab-ipadic-2.7.0-20070801.tar.gz
RUN (cd mecab-ipadic-2.7.0-20070801 \
&& ./configure --prefix=/var/task --with-charset=utf8 --with-mecab-config=/var/task/bin/mecab-config && make && make install)
RUN git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git
RUN yum install -y which xz patch openssl
RUN ln -s /var/task/bin/* /var/lang/bin/
RUN (cd mecab-ipadic-neologd && ./bin/install-mecab-ipadic-neologd -n -a -y)
COPY app.py requirements.txt ./
RUN python3.9 -m pip install -r requirements.txt -t .
# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]
mecabやmecabで使用するどデカい辞書をインストールしています。
どデカいのでbuildにはけっこう時間がかかりますが、Dockerfileなので一度行えばcacheが効き、プログラムの更新などの際のbuildはさほど時間がかからなくなります。
requirements.txt
requests
wheel
mecab-python3==1.0.4
もともとあったのrequestsとmecab-python3を入れるときに必要になったwheelを入れる予定
app.py
import os
import sys
import json
# preload libmecab
import ctypes
libdir = os.path.join(os.getcwd(), '/var/task/lib')
libmecab = ctypes.cdll.LoadLibrary(os.path.join(libdir, 'libmecab.so'))
import MeCab
# IPA辞書を利用
ipadic_tagger = MeCab.Tagger('-r /dev/null -d /var/task/lib/mecab/dic/ipadic')
# NEologdを利用
neologd_tagger = MeCab.Tagger('-r /dev/null -d /var/task/lib/mecab/dic/mecab-ipadic-neologd')
def lambda_handler(event, context):
keyword = event['queryStringParameters']['keyword']
print (ipadic_tagger.parse(keyword))
print (neologd_tagger.parse(keyword))
return {
"statusCode": 200,
'headers':{
'context-type':'text/plain'
},
"body": ipadic_tagger.parse(keyword),
}
build
buildを行います。
sam build
と実行するだけなので簡単。
※dockerに割り当ててるメモリが2GBだとコケたので3GB以上にする必要がありそうです。macだとPreferencesのResourcesから。
$ sam build
Building image for HelloWorldFunction function
Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/13 : FROM public.ecr.aws/lambda/python:3.9
---> b509e4dde698
Step 2/13 : RUN yum install -y file tar gzip unzip gcc make swig gcc-c++ git
......
Step 13/13 : CMD ["app.lambda_handler"]
---> Running in 29ad4bb3cd30
---> 6aab2db8b393
Successfully built 6aab2db8b393
Successfully tagged helloworldfunction:python3.9-v1
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {stack-name} --watch
[*] Deploy: sam deploy --guided
ローカルでテスト
sam local start-api
でローカルでテスト実行ができます。
$ sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2021-12-12 22:03:37 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
ブラウザで http://localhost:3000/hello?keyword=“裏切り者は誰だ!”世界的人気!2億ダウンロード「Among Us」宇宙船を舞台にした人狼ゲーム! みたいに開くとmecabの動作を確認できるはずです。
START RequestId: 27c6e221-ecb4-4ae3-b9ca-9f0101f4cba0 Version: $LATEST
“ 記号,括弧開,*,*,*,*,“,“,“
裏切り者 名詞,一般,*,*,*,*,裏切り者,ウラギリモノ,ウラギリモノ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
誰 名詞,代名詞,一般,*,*,*,誰,ダレ,ダレ
だ 助動詞,*,*,*,特殊・ダ,基本形,だ,ダ,ダ
! 記号,一般,*,*,*,*,!,!,!
” 記号,括弧閉,*,*,*,*,”,”,”
世界 名詞,一般,*,*,*,*,世界,セカイ,セカイ
的 名詞,接尾,形容動詞語幹,*,*,*,的,テキ,テキ
人気 名詞,一般,*,*,*,*,人気,ニンキ,ニンキ
! 記号,一般,*,*,*,*,!,!,!
2 名詞,数,*,*,*,*,2,ニ,ニ
億 名詞,数,*,*,*,*,億,オク,オク
ダウンロード 名詞,サ変接続,*,*,*,*,ダウンロード,ダウンロード,ダウンロード
「 記号,括弧開,*,*,*,*,「,「,「
Among 名詞,固有名詞,組織,*,*,*,*
記号,空白,*,*,*,*, , ,
Us 名詞,固有名詞,組織,*,*,*,*
」 記号,括弧閉,*,*,*,*,」,」,」
宇宙船 名詞,一般,*,*,*,*,宇宙船,ウチュウセン,ウチュウセン
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
舞台 名詞,一般,*,*,*,*,舞台,ブタイ,ブタイ
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
し 動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
人 名詞,一般,*,*,*,*,人,ヒト,ヒト
狼 名詞,一般,*,*,*,*,狼,オオカミ,オーカミ
ゲーム 名詞,一般,*,*,*,*,ゲーム,ゲーム,ゲーム
! 記号,一般,*,*,*,*,!,!,!
EOS
“ 記号,括弧開,*,*,*,*,“,“,“
裏切り者 名詞,一般,*,*,*,*,裏切り者,ウラギリモノ,ウラギリモノ
は 助詞,係助詞,*,*,*,*,は,ハ,ワ
誰だ 名詞,固有名詞,一般,*,*,*,誰だ,ダレダ,ダレダ
! 記号,一般,*,*,*,*,!,!,!
” 記号,括弧閉,*,*,*,*,”,”,”
世界的 名詞,固有名詞,一般,*,*,*,世界的,セカイテキ,セカイテキ
人気 名詞,一般,*,*,*,*,人気,ニンキ,ニンキ
! 記号,一般,*,*,*,*,!,!,!
2 名詞,数,*,*,*,*,2,ニ,ニ
億 名詞,数,*,*,*,*,億,オク,オク
ダウンロード 名詞,サ変接続,*,*,*,*,ダウンロード,ダウンロード,ダウンロード
「 記号,括弧開,*,*,*,*,「,「,「
Among 名詞,固有名詞,組織,*,*,*,*
記号,空白,*,*,*,*, , ,
Us 名詞,固有名詞,組織,*,*,*,*
」 記号,括弧閉,*,*,*,*,」,」,」
宇宙船 名詞,一般,*,*,*,*,宇宙船,ウチュウセン,ウチュウセン
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
舞台 名詞,一般,*,*,*,*,舞台,ブタイ,ブタイ
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
し 動詞,自立,*,*,サ変・スル,連用形,する,シ,シ
た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
人狼ゲーム 名詞,固有名詞,一般,*,*,*,人狼ゲーム,ジンロウゲーム,ジンロウゲーム
! 記号,一般,*,*,*,*,!,!,!
EOS
END RequestId: 27c6e221-ecb4-4ae3-b9ca-9f0101f4cba0
さくさくいきますね。Dockerfile使えるの便利すぎる
deploy
最後にdeployして完了です。 sam deploy --guided
でdeployが実行できます。2回目からは sam deploy
だけでいいです。
$ sam deploy --guided
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Not found
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: lambda-python-mecab-sam-example
AWS Region [ap-northeast-1]:
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: y
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]:
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: y
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
Looking for resources needed for deployment:
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-b1r5p8i4foj1
A different default S3 bucket can be set in samconfig.toml
Image repositories: Not found.
#Managed repositories will be deleted when their functions are removed from the template and deployed
Create managed ECR repositories for all functions? [Y/n]: Y
......
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
あとは待つだけ!
1GB超えの巨大なアプリケーションになってしまうのですが、ECR上にイメージが作られることになり、サイズ的な問題はクリアできます。
# 完成
そんなわけで無事にmecabの使用できる、巨大なLambdaをsam cliでbuildからdeployまでできました!
今回のコードはこちら
https://github.com/ikegam1/lambda-python-mecab-sam-example