日本語のオノマトペを3000個あつめてGAE/GoとFirebaseでサービスを作る

[![logo_full_fill.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532297/fb144390-ea94-0370-423b-6c4cfb47b3f2.png)](https://matopee.com)
https://matopee.com

Firebaseを管理画面側に、GAEを公開側に使って、日本語のオノマトペを集めて辞典などとして公開するサービスを作っています。まだまだ不足だらけですが、まずは3200件ちょっと集めた[オノマトペの五十音別全一覧](https://matopee.com/indexes/kana)を中心に公開しています。

[!["五十音全一覧のスクリーンショット。「あ」から「お」までのオノマトペの一部を抜粋している。"](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532297/152a0876-a217-3284-5a55-b5da602beba5.jpeg "オノマトペの五十音別全一覧")](https://matopee.com/indexes/kana)

オノマトペにも過不足がありますし、古語や方言はまだほぼ手つかずです。今後は地道に語義を増やし、分類し、論文や書籍、Webなどの参考情報を集め、幾つか毛色の違うコンテンツの準備をしよう、という状況です。


---

コメントで @scivola と @perpouh からいただいた以下のオノマトペなどを追加し、現在3340件になりました。

以下は語義付きで登録しました。

* [かこーん](https://matopee.com/words/かこーん)
* [ぐすぐす](https://matopee.com/words/ぐすぐす)
* [しみじみ](https://matopee.com/words/しみじみ)
* [ちんちくりん](https://matopee.com/words/ちんちくりん)
* [てれてれ](https://matopee.com/words/てれてれ)
* [どんぶらこ](https://matopee.com/words/どんぶりこ)

以下は登録のみ。
ざんぶ, じゃらん, じゃらーん, しゃらん, しゃりん, すぼっ, ぱったり, どっか, どっこいせ, どっこらせ, どわっはっは, にひにひ, ぬぼっ, ぱさり, はっし, ぱったり, ぱつんぱつん, ふうわり, ぶえっくし, ぶじゅ, ぶじゅぶじゅ, ぺたしぺたし, きらり

---

## オノマトペとは

サクサク、ぺったん、ガクブル、もちもち、どんより、ぐわーっ、ピシッなどは、すべてオノマトペです。

これらは"擬音語・擬態語・擬声語の総称"などと簡単に説明されていることが多いですが、定義は曖昧で、確立したものがありません。恣意性や音象徴性に着目しても一長一短で、合意を得られるような定義には至っていないようです。

サービスを作った動機の一つが、この定義を考える材料とすることでした。そのため、集めておきながら未だ定義がありません。ひとまず個人的な感覚を基準にしていますが、これを眺め、語義を考え、分類するなかで見出していこうと考えています。

### 日本語凄い論とオノマトペ

日本語はオノマトペが豊富な言語です。ただし世界の言語と比較すると、語数では上位グループの中位程度。オノマトペは決して日本語だけの特徴ではありませんし、際立って多くもありません。

しばしば「こんなにたくさんのオノマトペは日本語だけ！　特別！ すごい！」という主張を見かけますが、明らかな間違いです（[「日本だけで特別」という例](http://www1.odn.ne.jp/sanjinkai/bunka/kako/kakisemi14.html), [「日本語以外では重要でない、擬態語は日本語だけ」という例](http://www.switch-pub.co.jp/bd-natsume-fusanosuke-3/)）。
日本語が特別であってほしいという願望からなのか、単に英仏独辺り以外の言語を存在しないと思ってるのか、何にせよ誤りです。

### オノマトペの位置づけ

日本語のオノマトペの豊富さは特別ではありませんが、特徴のひとつではあります。また重要なのも確かで、現代では特に個人的感覚の表現において、用いないと困難だったり冗長だったりするほどです。

言語学では古くから扱われてはきたようですが、日本語で本格的な研究が盛んになったのは戦後しばらくしてからです。
通常公文書等には登場しませんが、報道や医療などでも活用されるケースがあります。いずれも感覚に訴えたりそれを受け取ったりという、曖昧だが重要な個人的な感覚の共有が、以前より重視されてきたことによると考えられます。

とはいえ厳密さが求められる場では、やはりオノマトペは排除されます。また幼稚だと毛嫌いされるなど、詩歌や文学などで一段落ちる扱いもしばしばされます。こうした扱いの原因はオノマトペの曖昧さにあると考えています。

個人的主観的で、非定量的で、多義的ゆえに、論理の伝達からは除かれる。あるいは、露骨で幼児的で、生々しく、変化しやすいゆえに、格調や洗練の表現からは除かれる。一方で、日常的には欠かせない言語要素であり、また漫画に於いては会話以上に重要な役割がある。

こうしたオノマトペの性質は、学術研究などでは進んでいても、広く一般にはあまり露出していません。そこでオノマトペの収集や分類、論文の紹介、用例の蓄積、またいずれはコーパスとしての提供など、諸々を扱う場がほしいと考えました。そしてどうせなら、そろそろ辞典を作りたいという欲求も合わせて、まずはオノマトペの辞典を作ることにしました。

## オノマトペの収集

集め始めた当時は収集をある程度仲間に任せ、Google Spreadsheetで管理していました。その時点で集めたのが700件強。ここで一旦企画は休止し、[日本語のオノマトペ一覧（暫定703件）](https://write.kogus.org/articles/G6P2yH)として公開しました。

その後仕切り直し、ひとりで登録することにしてからは[FileMaker](https://www.filemaker.com/jp/)での管理に切り替えました。
FileMakerは癖も強く古臭い所も多いですが、あまりに手に馴染んでいて、こうした用途には欠かせません。数十万件程度までは特に考えずに全文検索できますし、独特のリレーションシップさえ押さえれば、素早くロジック込みのフォームが用意できます。
今回の用途ではオノマトペの登録をブロックなく連続して行え、重複を防ぎ、表記ゆれや語長や文字種、語形などの確認をする、というフォームをFileMakerで作りました。実作業は15分程度。

このフォームに、過去に集めた700件強を取り込み、そこへ手入力でオノマトペを追加しました。ライセンスに縛られないデータとしたかったため、極力他の文献等は参照せず自分の記憶から入力。2000件程度までは順調でしたが、そこから3000件超えるまではやや苦しみました。3000件近く集まった辺りで、Firebaseによる管理に切り替えました。

## FirebaseとVue + Vuetifyで管理画面

![backstage.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532297/6f58a1d5-e8c7-72ff-27b0-8644dbdfd2cb.jpeg)

管理画面側にFirebaseを採用したのは、次の理由からです。

1. Google App EngineのDatastoreがFirestoreベースとなった
2. Authentication, Firestore, Hosting, Functionsと揃っている
3. ゲームやアプリのバックエンド用に練習しておきたい

色々思い違いもありましたが、結果的にいい経験となり、今後もWebベースの管理画面付きのサービスは同じ構成で行こうと考えています。ただしなんとなくVueExなしのJavaScriptではじめてしまったのは後悔していて、次は必ずTSの、最初にVueEx導入を検討します。

### 管理画面フルスクラッチ病とVuetify

昔から自前のサービスでは特に、毎回管理画面をフルスクラッチしたくなる病にかかっています。優れたライブラリがあっても、些細な点が気に入らずに「自分でライブラリ書くんだ！」と、中途半端なモジュールを書き散らかし、時間を無駄にしてきました。

自分のサービスの管理画面という、ほぼ自分がユーザーだから起きるだめな繰り返しですが、今回はいい加減この状況も変えようと、なんでもいいので一通り揃ったGUIのライブラリを採用すると決めました。「[なんとなくVue.jsのUIフレームワークを紹介する](https://qiita.com/yusuke_ten/items/4103f032dd0c6fbe5607)」などを見ながら、コンポーネントの豊富さと、Vue本体への追従が早そうなVuetifyを選択。

途中Vuetifyのメジャーバージョンが上がって手直しがありましたが、結果は満足しています。vue cliのおかげで、セットアップから開発サーバーまで一式揃いますし、Vuetifyのコンポーネントも色々活用できました。slotを使ったカスタマイズなども比較的柔軟で、特に[Data Tables](https://vuetifyjs.com/ja/components/data-tables)はごりごり使ってます。

### 管理画面の認証

以前のGoogle App Engineには、プロジェクトに管理者指定したGoogleアカウントしかアクセスできないapp.yamlのlogin: adminオプションが使えました。これはGoogleに全部投げられる手軽な管理者用認証でしたが、GAE独自のAPIが非推奨となっていき、最新のランタイムでは使えなくなりました。

当初、FirebaseのAuthenticationで、この代わりができそうだと誤解してしまいました。しかしFirebaseで用意されているGoogleアカウントのログインプロバイダは、GAEでいうUser API相当のもので、管理者アクセスの管理には使えませんでした。

結局[カスタム クレームとセキュリティ ルールによるアクセスの制御](https://firebase.google.com/docs/auth/admin/custom-claims)を参考に、Firestore, Functionsを組み合わせて実現しています。認証の流れは、Vueで未ログイン時用のAppを作り、そこでログインボタンとfirebase.auth().signInWithPopup(provider)による認証を行う、としています。管理者の追加にUIDが必要な点は少し面倒ですが、これで login: admin に近い管理ができています。

ただしVueアプリケーションをHostingで提供しているため、管理者のみがアクセスできるはずの静的なリソースに、認証せずアクセスできてしまいます。全てのリクエストをFunctions経由にする方法もありますが、それならGAEでホストした方がよっぽど手軽です。

もちろんFirestoreのrulesでは管理者のみ読み書きを許可していますし、パブリック側はGAEのサービスアカウントでFirestoreに触るため、Firestoreのデータにアクセスされる可能性はありません。それでも静的なリソースへのアクセスの可能性は残るため、この点が課題です。

### Firestoreのオフライン永続性とVuetifyのData Table

オノマトペは初期でも3000件程度あり、最大で数万件を想定しています。これをFirestoreのような従量制のDBで扱うと、readだけでもなかなかのコストが生じます。かといって、詳細なキャッシュの仕組みを時前で作りたくありません。

またFirestoreはクエリが貧弱というか、おまけのようなものなので、「"くに"を含んだ登録済みのオノマトペをざくっと見たい」「"◯る◯る"に該当するのは何件？」といった要求にも応えにくいです。

この問題を、Firestoreのオフライン永続性とVuetifyのData Tableを組み合わせて解決しました。

Firestoreには、PWAなどで使えるオフラインデータ永続性の機能が用意されています（[オフラインでデータにアクセスする](https://firebase.google.com/docs/firestore/manage-data/enable-offline?hl=ja)）。本来は名称の通りオフライン用の機能ですが、オンライン時にも手動で使えます。これにより一旦キャッシュに全件取得してしまえば、複雑なクエリに相当する問い合わせが、全てローカルで行えます。

取得したオノマトペは、Vuetifyの[Data Tables](https://vuetifyjs.com/ja/components/data-tables)で扱います。その名の通りデータ表示用の高機能なテーブルコンポーネントで、カスタムのフィルタやソートも柔軟に指定できるため、ややこしい要求にも応えられ、手抜きっぽくない見た目や基本機能が付いてきます。

## Google App Engine / Go でパブリック

管理画面はFirebaseを使いますが、パブリック側は使い慣れたGAE/Goを使っています。

SPAである必要性も薄く、readのみをサービスアカウントで実行するのでFirestoreのルールもadminのみ読み書きなシンプルな状態にできます。writeもありませんので、結果は全てCloudflareを通し、Page RulesでHTMLも含めた全キャッシュをかけています。

### Go 1.12のGAE/Go

Google App Engineは以前にまとめた状況（[2016年半ば現在のGoogle App Engine](https://write.kogus.org/articles/Y2Rtpp)）から、大きく変わりました。

最新のランタイムでは、もはやAppengine独自のAPIが使えません。詳しくは「[App EngineアプリをGo 1.12に移行する](https://cloud.google.com/appengine/docs/standard/go112/go-differences?hl=ja)」などにありますが、もはや我々の愛した閉じたGAEは死に、GCPの一員として、迅速なスケールとトラフィックの制御、バージョニングなどを特徴とした、コンピューティングの選択肢に過ぎなくなりました。

とはいえ移行してしまえば便利なもので、特にこれまで制約のあったインスタンスが一般的なLinuxに近い状態となったことで、ポータビリティは格段に上がっています。どこで実行しても動くGoのアプリケーションを作れば、app.yamlを足すだけでGAEでも動くのです。dev_appserver.pyは懐かしいですが、戻りたくはありません。

## 今後

足りないものを追加したり、統合すべき表記揺れや誤りの削除などしつつ、語義をどんどん追加していきます。まずは辞典として充実させつつ、分類や論文などを増やしていきます。

もしオノマトペの過不足や、その他ご指摘があれば、ぜひ[@matopeeja](https://twitter.com/matopeeja)までください。

---

![https---qiita-image-store.s3.amazonaws.com-0-56480-833eda6a-d997-fdfd-036f-ca7a549b84f6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532297/48068b15-bc29-5012-4c58-6195558d8f71.png)