Windows7環境なのにdocker入れて開発することになった話【②システム構成編】

# はじめに
[1章](https://qiita.com/Shunichirou/items/ce7cc3c69eef690e08a8)では、環境構築をしてきました。しかし、どのようなアプリケーションを作るか、何も考えていませんでした。基盤は整ったものの、何を作るか決めないことにはシステムは開発できません（当たり前）。そこで、本章は以下の順序で記述していきたいと思います。

- 要件の検討
- システム構成の検討
- 不足していたライブラリ・ソフトウェアの導入
- 動作確認

まだまだタイトルのdockerに触れるには時間がかかりそうで、タイトル詐欺もいいところですが、是非一読ください。1章同様、指摘・要望お待ちしております。


# 辞書整理
本文章（第2章）を読む上で頭に入れておいたほうが良い文言をピックアップ。文中分からない文言が出たら見返してください。（不足あれば、コメントいただけたら追記していきます）

- スクレイピング
    - WebページからHTMLデータを収集・抽出し、整形・加工すること。
    - 似たワードにクローリングがあるが、クローリングはサイトを巡回し、情報を取得することを指す
    - 基本は、個人の私的利用の範囲に限る【参考2】
    - GUIベースのフリーソフトもあるが、どの情報を抽出してくるか自由がきかないものが多い【参考3】
    - プログラミングをする際は、Python、Ruby、JavaScriptにスクレイピング用のライブラリが有る
    - ライブラリが無くとも、取得したいURLにHTTPリクエストを行い、HTMLを取得、正規表現を用いるなどして情報を取得することは可能（あくまでライブラリは、それを簡単に行えるようにしているだけ）
    - 今回は、PythonのライブラリであるBeautifulSoup4を利用する【参考1】
    - [参考1：【Pythonクローラー入門】クローリング スクレイピング方法 総まとめ](https://www.sejuku.net/blog/69383)
    - [参考2：Webスクレイピングの注意事項一覧](https://qiita.com/nezuq/items/c5e827e1827e7cb29011)
    - [参考3：悪用厳禁！プログラミング不要のWEBスクレイピングツール比較19選](http://t-shimohara.com/programming/scraping)

- MeCab
    - NLP（自然言語処理）を行うにあたって、形態素解析を行うことができるオープンソース
    - 辞書を用いて文章を形態素（単語として意味を持つ最小の単位）に分解し、品詞やタグを付属することができる
    - 『形態素解析→類似度（どの程度似た意味の単語か）判定』や、『形態素解析→機械学習』のように、文字列を扱うための前処理として利用される
    - うまく形態素として分解されない（もしくは利用したい単語よりもさらに細分化されてしまう）ワードのために、ユーザー定義辞書を作成することが可能（例えば機械学習を、「機械」と「学習」に分けたくない場合など）
    - [参考：【技術解説】形態素解析とは？MeCabインストール手順からPythonでの実行例まで](https://mieruca-ai.com/ai/morphological_analysis_mecab/)

- AWS CLI
    - AWS上のサービスに対して、ローカル環境やEC2（AWS上の仮想サーバ）からコマンドラインベースで接続することを可能にするツール（コマンドプロンプトやターミナルから、AWSを操作するコマンドを実行できるようにする）
    - コンソール（ログインしてGUI上でAWSを触る）でできることは、基本的に全てCLIで実行可能
    - S3（AWS上のストレージサービス）に置いてあるデータを、ローカルやEC2から覗いたり、コピーしたりすることもできる
    - 今回の場合、ローカル環境からDynamoDBへアクセスし、テーブルを作成する際に利用する
    - [参考：AWSコマンドラインインターフェイス（公式）](https://aws.amazon.com/jp/cli/)


※数あるクラウドサービスの中で、AWSの公式ドキュメントが一番読みやすくまとまっている（気がする）

- DynamoDB
    - NoSQLデータベース
    - データ構造はRDBとは異なり、KVS（キーとレコードが１：１、場合によっては２：１で結びつく）構造
    - 高速なデータアクセス、書き込み
    - テーブルの結合できない
    - 主キーは2つまで
    - 各レコードが同一の項目数でなくても良い
    - Pythonで言う辞書型（Json）の構造でデータの出し入れができる
    - 変化に強く、テーブル設計が楽（不要とは言っていない）
    - 横方向スケール等、改修時の手間が少ない

- ECS
    - Elastic Container Serviceの略で、AWS上でDockerコンテナをサポートする、コンテナオーケストレーション（複雑なコンピュータシステム/ミドルウェア/サービスの配備/設定/管理の自動化）サービス
    - コンテナ化されたアプリケーションを、簡単に実行・デプロイすることが可能となる
    - コンテナ化されたアプリケーションをAWS上で活用するためには、サーバをプロビジョニング（準備の意で、EC2上でCLIを利用し、docker等のコンテナを扱うソフトウェアを導入する）し、クラスタリング（docker-compose等で複数サーバ、コンテナを統合し、１つのサーバシステムのように扱う）必要があった。ECSの登場で、そういった管理、デプロイ等を不要とし、GUI上で簡易にコンテナアプリケーションを導入することが可能となった
    - とはいえ内部ではEC2が起動され、統合的に管理されている
    - [参考：Amazon Elastic Container Serviceの特徴](https://aws.amazon.com/jp/ecs/features/)

- Fargate
    - ECSの登場により、簡単にコンテナアプリケーションをAWS上に実現できるようになった。とはいえ、内部で動作するEC2のインスタンスタイプ選択や、スケールの調節が必要であった
    - 起動中にEC2コンソールを見ると、インスタンスが立ち上がっていることも確認できた
    - Fargateは、そもそもユーザからはEC2が見えず、スケールや管理も全てよろしくやってくれる
    - 現在は、ECSを立ち上げる際に、EC2上でコンテナ起動をするか、Fargateでよろしくやらせるか選択することができる
    - [参考：AWS ECSとFargateの組み合わせが素晴らしい件)](https://tech.mti.co.jp/entry/2017/12/06/190200)
    - [参考：ECSのバックエンドをEC2からFargateに変更するにあたり知っておくとよさそうな事](http://tech.connehito.com/entry/2018/09/05/164805)

- boto3
    - AWS SDK for Python
    - PythonでAWS環境を触るために必要なライブラリ
    - AWS上のサービスを指定して、稼動・停止、各種操作等がPython上から行うことができる
    - 今回の場合、ローカル環境からDynamoDBへアクセスし、データ操作をする際に利用する
    - AWS Translateを利用してNewsタイトルを翻訳する際にも利用する予定
    - [参考：AWS SDK for Python (Boto3)]https://aws.amazon.com/jp/sdk-for-python/)

# 必要なソフトウェアのインストール

第2章では必要なライブラリをインストールしていきます。また、当章以降は以下を前提としてシステム構築を行っていきます。

- [第1章](https://qiita.com/Shunichirou/items/ce7cc3c69eef690e08a8)でUbuntu環境が構築されている
- Python(pip含め)がインストールされている
    - 次の理由から、どれだけ手順を踏んでも個人間の環境で差異が起きやすいため、Pythonのインストール方法については敢えて言及しません
        - Pythonのインストールは様々な方法がある（そもそもUbuntuには最初からインストールされていたりする）
        - 頻繁にバージョンアップデートがされる
        - pyenv等で複数バージョン（2系と3系）を1環境に導入できる
        - Anacondaのような、Pythonで便利なライブラリを一元管理してくれるディストリビューション上で開発もできる([参考：Anaconda は Environment Isolation Tool (環境分離ツール) ではない](https://qiita.com/t2y/items/dd6d7f9c70ac2b8a79da))
        - とはいえ私も参考にした資料は有り、[Pythonの環境構築を自分なりに整理してみる](https://medium.com/@chezou/python%E3%81%AE%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%82%92%E8%87%AA%E5%88%86%E3%81%AA%E3%82%8A%E3%81%AB%E6%95%B4%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B-dc8d8f2fe989)を参考にして環境構築しました
- AWSコンソール上にログインできる環境がある

※上記記事内では「`$sudo pip install ○○`はグローバル空間に入ってしまうためダメです」的なことが書かれていますが、今回は説明を簡単にするために無視しています

※管理ユーザ、パーミッションの都合上sudoをつける必要がある場面もあるかと思いますが、当記事ではsudoは全て省いています


## 1.Pythonに必要なライブラリのインストール
今回必要なライブラリは、以下の通り。全て`$pip install hogehoge`でインストール可能。（Anaconda環境を利用している人はpip厳禁です）

- BeautifulSoup4
    - スクレイピングに利用
    - `$pip install beautifulsoup4`
- boto3
    - Python上で、AWSの各サービスにアクセスするために利用
    - `$pip install boto3 beautifulsoup4`
- MeCab
    - Python上で、MeCabの機能を利用するために利用
    - `$pip install mecab-python3`

## 2.MeCabのインストール及び環境セットアップ
MeCabを利用するためのライブラリはPython側で導入したが、MeCabそのものがインストールされていないため、順次インストールを行います。MeCabは、「ツール本体＋設定ファイル＋システム辞書＋（ユーザ辞書）」から成り、それぞれインストールが必要。通常ネオロード等の用意されている辞書（システム辞書）を使うが、うまく形態素解析ができない場合、欲しいワードがネオロード上では違う品詞と解釈されていた場合、またワードへのタグ付けを行いたい場合のために、ユーザ辞書を作成することができます。


- MeCab本体のインストール（このタイミングで設定ファイルもインストールする）
    - `$sudo apt-get install mecab mecab-ipadic libmecab-dev`
        - mecab-ipadicを入れることで、MeCabで扱う文字コードがUTF-8になります
        - libmecab-devを入れることで、mecab-config（設定ファイル）が利用できるようになります
- mecab-ipadic-neologd（通称ネオロード）のインストール
    - `$git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git <保存する場所のパス>`
    - `$cd <保存した場所>/mecab-ipadic-neologd`
    - `$./bin/install-mecab-ipadic-neologd -n`

この次点で（私の場合）環境は以下のようになっている。
※自己の環境で各インストール先のファイルパスが分からなかった場合は、トップのフォルダから`$find / -name ファイル名`で全検索できます


```参考
- mecab-dict-index（ユーザ辞書作成に必要なコンパイラ）
    - /usr/lib/mecab/mecab-dict-index

- システム辞書
    - /var/lib/mecab/dic/mecab-ipadic-neologd

- MeCabの設定ファイル
    - /etc/mecabrc
```

- ユーザ辞書の作成
    - ユーザ辞書用のフォルダ（私の場合は/home/user名/userDic）に、以下の定義（select_dic.csv）でcsvファイルを作成する
    - csvファイルの存在するフォルダに移動し、次のコマンドでコンパイルする<br />
`$/usr/lib/mecab/mecab-dict-index（環境次第でパスは変更） -d ＜システム辞書が入っているディレクトリ＞ -u ＜ユーザ辞書の保存先＋ファイル名＞ -f ＜CSVファイルの文字コード＞ -t ＜ユーザ辞書の文字コード＞ ＜CSVファイル＞`

※私の環境の場合は、次のコマンドになる<br />
`$/usr/lib/mecab/mecab-dict-index -d /usr/lib/mecab/dic/mecab-ipadic-neologd -u /home/user名/userDic/select_dic.dic -f utf-8 -t utf-8 select_dic.csv`


<ユーザ辞書の例>

```select_dic.csv

定義）表層形, 左連接状態番号, 右連接状態番号, コスト, 品詞, 品詞細分類1, 品詞細分類2, 品詞細分類3, 活用型, 活用形, 基本形, 読み, 発音,（タグ）
例1）量子コンピュータ,-1,-1,-1,名詞,一般,*,*,*,*,*,*,*,selectdic
例2) 買収,-1,-1,-1,名詞,一般,*,*,*,*,*,*,*,selectdic
例3) 量子,-1,-1,-1,名詞,一般,*,*,*,*,*,*,*,selectdic
```

※必須項目は、最初から4項目、「表層形, 左連接状態番号, 右連接状態番号, コスト」であり、残りの項目は自由に設定可能。タグ以外の項目については、一般的なシステム辞書で管理されている項目となる。

※最初の表層形（単語そのもの）及び最後のタグさえ正しい値が入っていれば、今回のシステムは動きます。必須項目である「左連接状態番号, 右連接状態番号, コスト」の数値はいくつでも問題ありません。詳しくは[参考：日本テレビ東京で学ぶMeCabのコスト計算](http://www.mwsoft.jp/programming/munou/mecab_nitteretou.html)を参照ください。

- 設定ファイルに、ユーザ辞書を追加する
    - MeCabの設定ファイル、mecabrc（私の場合/etc/mecabrc）を開き、先ほど作成したユーザ辞書のパスを追加する

```mecabrc
userdic = /home/user名/userDic/select_dic.dic
```

## 3.AWS CLIのインストール及びセットアップ
DynamoDBにローカルからアクセスするために、AWS CLIをインストールします。（なくても、コンソール上でGUIでTableを作成もできます）

- AWS CLIのインストール
    - `$ pip install awscli`

- AWSアクセス情報の設定ファイル編集
    - `$aws configure`

```
AWS Access Key ID [None]: xxxxxxxxxx（IAMユーザ作ったを際のアクセスキー）
AWS Secret Access Key [None]: xxxxxxxxxx（IAMユーザ作ったを際のシークレットアクセスキー）
Default region name [None]: ap-northeast-1（開発を行っているリージョン）
Default output format [None]: json（出力形式）
```

# 各種動作確認
ソフトウェアのインストールが終わったので、「スクレイピング」、「MeCab」、「AWS CLI」の順で動作確認を行います。

## スクレイピングの動作確認
![スクレイピング対象画面](https://drive.google.com/uc?export=view&id=19zyT0EC2Kk-8M7aWvWl0mFJMNyjdT0vL)

とあるニュースサイトより、情報を取得します。必要な情報は、今のところはニュースタイトルと、タイトルからリンクする際のURLのみとします。スクレイピングの基本は、以下の順序でコードを記載します。

1. スクレイピング対象のURLに対してリクエスト送信
2. DOMツリー（HTMLのようなタグでネストされた構造）の取得
3. DOMツリーの解析

### スクレイピングソースコード

```python

# スクレイピング用ライブラリのインポート
from bs4 import BeautifulSoup 
# HTTP通信用ライブラリのインポート（標準）
import urllib.request, urllib.parse

####### 変数解説 #######
# url : スクレイピング対象のURL
# parser : HTML解析器
# headers : firefoxに偽装するためのユーザーエージェントヘッダー

url = "https://finovate.com/blog/"
parser = "html.parser"
headers = {
    "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0",
        }

# HTTP通信を行いホームページにrequest、HTMLの取得
request = urllib.request.Request(url = url, headers = headers)
html = urllib.request.urlopen(request).read().decode("utf-8")

# パーサーのインスタンス化
parser = BeautifulSoup(html, parser)

# タイトルが記載されている、h2, aタグがネストされたリストを取得
# 実際にHTMLを確認し、どのように解析すればほしい情報が取得できるか解析する必要がある
allh2Tag = parser.select("h2 a")

# h2, aタグのネストされたリストから、必要な情報を取得
for tag in allh2Tag:
    url = tag.get("href")
    title = tag.string
    print("url : " + url)
    print("title : " + title + "\n")
```


### スクレイピング実行結果

```
url : https://finovate.com/ntt-data-services-to-acquire-sierra-systems/
title : NTT DATA Services to Acquire Sierra Systems

url : https://finovate.com/quid-lands-37-5-million-round-led-by-lexis-nexis-parent/
title : Quid Lands $37.5 Million Round Led by Lexis Nexis Parent

url : https://finovate.com/finovate-alumni-news-871/
title : Finovate Alumni News

url : https://finovate.com/welcome-to-finovateasia-2/
title : Welcome to FinovateAsia

url : https://finovate.com/welcome-to-wan-chai-finovateasia-kicks-off-hong-kong-fintech-week/
title : Welcome to Wan Chai: FinovateAsia Kicks Off Hong Kong FinTech Week

url : https://finovate.com/swych-powers-wechats-travelex-pay-service/
title : Swych Powers WeChat’s Travelex Pay Service

url : https://finovate.com/finovate-alumni-news-870/
title : Finovate Alumni News

url : https://finovate.com/yoyo-lands-30-million-partnership-agreement/
title : Yoyo Lands $30 Million Partnership Agreement

url : https://finovate.com/ondeck-partners-with-pnc-bank-to-streamline-sme-financing/
title : OnDeck Partners with PNC Bank to Streamline SME Financing

url : https://finovate.com/finovateasia-is-days-away/
title : FinovateAsia is Days Away
```

対象のニュースが取得できていることが分かります。

※「3.DOMツリーの解析」について、いかに汎用的なソースコードを書いたとしても、ホームページによってDOMツリーの構造は大きく異なります。今回対象としたサイトはh2,aタグのネストされた構造が全てニュースタイトルであったため簡単に取得できてますが、div,spanタグや、各タグのクラス定義によっては、複雑なコードをかく必要が有ります。対象のホームページの数だけ、最初のコスト及び保守コストがかかるため、実装前に、どのホームページを対象とするかは吟味することをおすすめします。

※今回はh2,aタグのみ取得するだけなので簡単に解析を行えていますが、実際はBeautifulSoupのメソッドを駆使して、どうにか必要な情報を取得できる場合がほとんどです。そういった際に参考にできるサイトはこちらです。[参考：BeautifulSoup4のチートシート(セレクターなど）](https://python.civic-apps.com/beautifulsoup4-selector/)

## MeCabの動作確認

ニュースタイトルの中にあるワードが見つかった場合、MeCabのユーザ定義の辞書に引っ掛けて取得するような仕組みを実現します。（実際は、MeCabは日本語の形態素解析器であるため、スクレイピング対象が英語のサイトであった場合は、AWS Translateにて翻訳した上で辞書に掛けています）

当記事のMeCab環境構築の中で、ユーザ辞書に以下の定義が追加されています。この状態で、次のワードを形態素解析してみたいと思います。

- 「量子コンピューターの「米中競争」が過熱──競り合うグーグルとアリババは、量子超越性を達成できるか」
    - ⇒辞書登録されているワード、「量子」が含まれる
    - ⇒「量子コンピューター」については、辞書登録されたワードと少し異なる
- 「中国アリババのクラウド事業がAWS並のバケモノになりつつある件」
    - ⇒辞書登録されているワードが含まれていない


```select.csv
量子コンピュータ,-1,-1,-1,名詞,一般,*,*,*,*,*,*,*,selectdic
買収,-1,-1,-1,名詞,一般,*,*,*,*,*,*,*,selectdic
量子,-1,-1,-1,名詞,一般,*,*,*,*,*,*,*,selectdic
```

### 形態素解析ソースコード

```python
# 形態素解析用ライブラリのインポート
import MeCab

# MeCabのどのシステム辞書を使うか指定
mecab = MeCab.Tagger("-d /var/lib/mecab/dic/mecab-ipadic-neologd")
#おまじない⇛これがないと文字コードエラーが起きる模様
mecab.parse("")

# 対象のニュースタイトル１つ目
test_text = "量子コンピューターの「米中競争」が過熱──競り合うグーグルとアリババは、量子超越性を達成できるか"
mecab_node = mecab.parseToNode(test_text)

print("ニュースタイトル① : " + test_text)

# すべての形態素（単語）に対して解析を行う
while mecab_node:
    
    print("原型 : " + mecab_node.surface)
    print("形態素 : " + mecab_node.feature)
    
    # 形態素を分割
    detail = mecab_node.feature.split(",")
    
    # 形態素の10番目に値が入っている場合、出力
    # ⇛ユーザ辞書で登録されているワードであることが確認できる
    try:
         print(detail[9] + "⇛ユーザ辞書に膨れまれているワードです\n")
    except IndexError as e:
        pass

    mecab_node = mecab_node.next
    
print("---------------------------------------------------------------------------")

# 対象のニュースタイトル2つ目
test_text2 = "中国アリババのクラウド事業がAWS並のバケモノになりつつある件"
mecab_node2 = mecab.parseToNode(test_text2)

print("ニュースタイトル② : " + test_text2)
# すべての形態素（単語）に対して解析を行う
while mecab_node2:
    
    print("原型 : " + mecab_node2.surface)
    print("形態素 : " + mecab_node2.feature)
    
    detail = mecab_node2.feature.split(",")
    
    # 形態素の10番目に値が入っている場合、出力
    # ⇛ユーザ辞書で登録されているワードであることが確認できる
    try:
         print(detail[9] + "⇛ユーザ辞書に膨れまれているワードです\n")
    except IndexError as e:
        pass

    mecab_node2 = mecab_node2.next 
```

### 形態素解析実行結果
```
ニュースタイトル① : 量子コンピューターの「米中競争」が過熱──競り合うグーグルとアリババは、量子超越性を達成できるか
原型 : 
形態素 : BOS/EOS,*,*,*,*,*,*,*,*
原型 : 量子コンピューター
形態素 : 名詞,固有名詞,一般,*,*,*,量子コンピュータ,リョウシコンピューター,リョーシコンピューター
原型 : の
形態素 : 助詞,連体化,*,*,*,*,の,ノ,ノ
原型 : 「
形態素 : 記号,括弧開,*,*,*,*,「,「,「
原型 : 米中
形態素 : 名詞,固有名詞,人名,姓,*,*,米中,ヨネナカ,ヨネナカ
原型 : 競争
形態素 : 名詞,サ変接続,*,*,*,*,競争,キョウソウ,キョーソー
原型 : 」
形態素 : 記号,括弧閉,*,*,*,*,」,」,」
原型 : が
形態素 : 助詞,格助詞,一般,*,*,*,が,ガ,ガ
原型 : 過熱
形態素 : 名詞,サ変接続,*,*,*,*,過熱,カネツ,カネツ
原型 : ─
形態素 : 記号,一般,*,*,*,*,─,─,─
原型 : ─
形態素 : 記号,一般,*,*,*,*,─,─,─
原型 : 競り合う
形態素 : 動詞,自立,*,*,五段・ワ行促音便,基本形,競り合う,セリアウ,セリアウ
原型 : グーグル
形態素 : 名詞,固有名詞,組織,*,*,*,Google LLC,グーグル,グーグル
原型 : と
形態素 : 助詞,並立助詞,*,*,*,*,と,ト,ト
原型 : アリババ
形態素 : 名詞,固有名詞,一般,*,*,*,アリババ,アリババ,アリババ
原型 : は
形態素 : 助詞,係助詞,*,*,*,*,は,ハ,ワ
原型 : 、
形態素 : 記号,読点,*,*,*,*,、,、,、
原型 : 量子
形態素 : 名詞,一般,*,*,*,*,*,*,*,selectdic
selectdic⇛ユーザ辞書に膨れまれているワードです

原型 : 超越
形態素 : 名詞,サ変接続,*,*,*,*,超越,チョウエツ,チョーエツ
原型 : 性
形態素 : 名詞,接尾,一般,*,*,*,性,セイ,セイ
原型 : を
形態素 : 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
原型 : 達成
形態素 : 名詞,サ変接続,*,*,*,*,達成,タッセイ,タッセイ
原型 : できる
形態素 : 動詞,自立,*,*,一段,基本形,できる,デキル,デキル
原型 : か
形態素 : 助詞,副助詞／並立助詞／終助詞,*,*,*,*,か,カ,カ
原型 : 
形態素 : BOS/EOS,*,*,*,*,*,*,*,*
---------------------------------------------------------------------------
ニュースタイトル② : 中国アリババのクラウド事業がAWS並のバケモノになりつつある件
原型 : 
形態素 : BOS/EOS,*,*,*,*,*,*,*,*
原型 : 中国
形態素 : 名詞,固有名詞,地域,国,*,*,中国,チュウゴク,チューゴク
原型 : アリババ
形態素 : 名詞,固有名詞,一般,*,*,*,アリババ,アリババ,アリババ
原型 : の
形態素 : 助詞,連体化,*,*,*,*,の,ノ,ノ
原型 : クラウド
形態素 : 名詞,固有名詞,一般,*,*,*,CROWD,クラウド,クラウド
原型 : 事業
形態素 : 名詞,一般,*,*,*,*,事業,ジギョウ,ジギョー
原型 : が
形態素 : 助詞,格助詞,一般,*,*,*,が,ガ,ガ
原型 : AWS
形態素 : 名詞,固有名詞,一般,*,*,*,エーダブリューエス,エーダブリューエス,AWS
原型 : 並
形態素 : 名詞,一般,*,*,*,*,並,ナミ,ナミ
原型 : の
形態素 : 助詞,連体化,*,*,*,*,の,ノ,ノ
原型 : バケモノ
形態素 : 名詞,固有名詞,一般,*,*,*,バケモノ,バケモノ,バケモノ
原型 : に
形態素 : 助詞,格助詞,一般,*,*,*,に,ニ,ニ
原型 : なり
形態素 : 動詞,自立,*,*,五段・ラ行,連用形,なる,ナリ,ナリ
原型 : つつ
形態素 : 助詞,接続助詞,*,*,*,*,つつ,ツツ,ツツ
原型 : ある
形態素 : 動詞,自立,*,*,五段・ラ行,基本形,ある,アル,アル
原型 : 件
形態素 : 名詞,一般,*,*,*,*,件,ケン,ケン
原型 : 
形態素 : BOS/EOS,*,*,*,*,*,*,*,*

```

実行結果を確認すると、「量子」というワードに辞書がヒットしている様子が分かります。「量子コンピューター」については、辞書に登録されていたワードが「量子コンピュータ」であったため、ヒットしないところも正確に実現できています。

上記の結果から、ユーザ辞書に登録してあるワードについて、ピックアップしてくることが可能なことが分かりました。ユーザ辞書の自動更新（追加、削除）、単語ごとの重み付け（文中に現れてくる回数等、注目度から算出）が実現できれば、より必要なニュースが抽出できそうな気がしてきました。

## AWS CLI及びboto3の動作確認
以下の順序で、DynamoDBにテーブルを構築して、データを出し入れします。

1. AWS CLI上からニュースを格納するためのテーブルの構築
2. Pythonからboto3を利用してデータの出し入れを行う

### テーブルに対応するjsonファイルを作成する

KeySchemaによって、ハッシュキーとソートキーを設定します。主キーが1つである場合は、ハッシュキーのみで問題ありません。RDB形式とは異なり、TBL作成をする際にカラム名を指定する必要がある項目はキー項目のみです。今回の例では、一意になる項目としてニュース単位にIDを付与するため、ハッシュキーのみでも問題ありません。


```tableDef.json
{
  "TableName": "NewsTable",
  "AttributeDefinitions": [
    {
      "AttributeName": "id",
      "AttributeType": "S"
    },
    {
      "AttributeName": "category",
      "AttributeType": "S"
    }
  ],
  "KeySchema": [
    {
      "KeyType": "HASH",
      "AttributeName": "id"
    },
    {
      "KeyType": "RANGE",
      "AttributeName": "category"
    }
  ],
  "ProvisionedThroughput": {
    "WriteCapacityUnits": 5,
    "ReadCapacityUnits": 5
  }
}
```

AttributeNameはカラム名、AttributeTypeは型指定で、SはStringをあらわす。一覧については[サポートされているデータの種類](https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/DynamoDBMapper.DataTypes.html)を参照ください。

### awsコマンドを用いてテーブルを作成する

ファイルの置いてあるフォルダに移動し、以下コマンドを実行します。
`$aws dynamodb create-table --endpoint-url http://localhost:8000 --cli-input-json file://tableDef.json`

※--endpoint-urlは、ローカル環境にDynamoDBを立てて実行した場合に必要な引数です。実際にAWS上のDynamoDBを更新する場合は、既にawsコマンドと自分のコンソールが紐づくように設定ファイル（configure）を記載しているため、エンドポイントを指定する必要は有りません。

コンソールを開き、テーブルが作成されていることが確認できました。

![テーブル](https://drive.google.com/uc?export=view&id=1MBPZxvmzl6Nn1dModnXj4zn0vTDa08PZ)

### boto3からデータの出し入れを行う

AWS CLIから作成したテーブルに対して、Pythonからデータの出し入れを行います。boto3についてもAWS CLI同様に、設定ファイル（configure）の情報を読むことで、AWSの個人コンソールにアクセスを可能としています。

### データアクセス用ソースコード

```python

import boto3
from boto3.dynamodb.conditions import Key, Attr
import sys

# NewsTableへのdaoのアクセス定義
# localの場合
# dynamodb = boto3.resource('dynamodb',endpoint_url='http://localhost:8000')
# AWS DynamoDBサービスの東京リージョン(ap-northeast-1)を指定
dynamodb = boto3.resource('dynamodb',region_name='ap-northeast-1')
table = dynamodb.Table('NewsTable')

sys.setrecursionlimit(100000)

# NewsTableに対応したDao
class NewsTableDao:

    def __init__(self):
        pass

    # 各レコードに対応したニュース（辞書型）を渡すことで、一括登録するメソッド
    def saveNews(self, news):
        
        table.put_item(Item = news)
            
    # scan（全量取得）したデータに対して、day項目で絞って取得するメソッド
    def selectNewsList(self, day):
        
        JaNewsList = table.scan(FilterExpression = Attr('day').eq(day))
        return JaNewsList

# NewsTableに登録するNewsに対応したオブジェクト用クラス
class News:

    def __init__(self, id, category, day, time, news, url):
        self.id = id
        self.category = category
        self.day = day
        self.time = time
        self.news = news
        self.url = url

    def to_dict(cls):

        return {
        "id" : cls.id,
        "category" : cls.category,
        "day" : cls.day,
        "time" : cls.time,
        "news" : cls.news,
        "url" : cls.url
        }

def main():
    
    id = "001"
    category = "Cloud"
    day = "20180101"
    time = "000000"
    news = " 量子コンピューターの「米中競争」が過熱──競り合うグーグルとアリババは、量子超越性を達成できるか"
    url = "http://xxxxxxyyyyy"

    # ニュースの各変数をBean（Newsクラス）に格納
    news = News(id, category, day, time, news, url)

    newsDao = NewsTableDao()
    
    # ニュースの登録
    newsDao.saveNews(news.to_dict())
    
    # 登録したニュースの取得
    print(newsDao.selectNewsList(day)['Items'])

    
if __name__ == '__main__':
    main()
```

### データアクセス実行結果

```
[{'category': 'Cloud', 'time': '000000', 'day': '20180101', 'id': '001', 'url': 'http://xxxxxxyyyyy', 'news': ' 量子コンピューターの「米中競争」が過熱──競り合うグーグルとアリババは、量子超越性を達成できるか'}]

```

うまくデータが取得できており、DynamoDBにデータが登録されていることが分かります。


[第三章:③docker開発環境編](https://qiita.com/Shunichirou/items/331845b20f37f6c875a2)へ続く