elasticsearchのdateでepoch_secondを使用する
経緯
普段はpythonを使用している。 日付関連は基本的にtimestampを使用している。 pythonのdatetimeモジュールにおけるtimestampは秒単位(10桁)になっている。
一方でelasticsearchのtype: dateはmillisecになっている。 elasticsearchにindexするときに、日付データを1000倍にする。取り出す時に1000分の1にするという方法もあるけど間違えそう。
また、検索についてはisoformatを使って柔軟に処理したいというニーズもある。
ということで、 - データ投入ではtimestampを使用 - クエリではtimestampもisoformatも柔軟に対応できる そんな方法はないと悩んだ次第である。
解決策
formatを使用して解決した。 以下はmappingsの抜粋。
"created_at": { "type": "date", "format": "epoch_second||date_optional_time" }
formatは||を指定することで複数指定可能である。 今回は - epoch_second(millisecondsではなくて) - date_optional_time を登録してみた。
以下は投入データとクエリの例 とりあえずやりたいことはできている。
PUT /test/_doc/1 { "created_at": 1577876400 //10桁timestampで投入可 } GET /test/_search { "query": { "range": { "created_at": { "from": "2020-01-01T20:00:00" //フルisoformat } } } } GET /test/_search { "query": { "range": { "created_at": { "from": "2020-01-01T20:00:00.000" //millisecまで込みのフルisoformat } } } } GET /test/_search { "query": { "range": { "created_at": { "from": "2020-01-01T20" // 欠落しててもOK } } } } GET /test/_search { "query": { "range": { "created_at": { "from": 1599999999, // 10桁timestamp "to": 1600000001 } } } }
最後に
日付関連はめんどくさい。
【小ネタ】エディタで正規表現をつかって一括でcamelCaseをsnake_caseに変換する
経緯
顧客のRDBをDynamoDBに入るようにモデリングしなおして、データマイグレーションを行っている。
当社のDBのattributeはスネークケース(単語と単語をアンダースコアで結ぶ。例:snake_case)を使用しているが、顧客のDBやソースコードはキャメルケース(先頭単語は小文字で単語と単語の切れ目は大文字にして区別。例: camelCase)を使用している。
ドキュメント作成段階においては、頻繁に書き換えが起きているのだがエディタで一括変換が簡単にできるのがわかったので記しておく。
方法
上記はvscodeの例です。
- 大文字・小文字の区別をつけるオプション(Aa)をオンにする
- 正規表現(.*)をオンにする
- 上部分で大文字をキャッチしたいので[A-Z]
- その大文字部分をキャプチャしたいので()で囲む
- 下部分で\Lをつけてキャプチャした内容($1)で小文字に変換。直前に_をつける。
ということで一括変換ができました。
感想
変数の命名規則の付け方はプロジェクトごとに決まることが多いと思います。
キャメルケースの場合だと全部大文字にしたい単語(ID, FAX ... etc)があると切れ目がわからなくなるのでスネークケースの方が好みなのですが、
一括変換ができるのでもうほんとどっちでもいいなおいう気持ちになりました。
C++をやってみる
経緯
『プログラマーが知るべき97のこと』を読んでいて、他のパラダイムの言語を習得することで、元の言語の理解も深まる旨記載があった。
目下、目の前の仕事を楽にするにはもっとコーディングがうまくなる必要があると考えている。
コーディングが上手いってなんだろう。。。と考えてみるとどうやら3つくらいにわかれるのかもしれない。
- アルゴリズムとデータ構造をしっかり理解し、メモリや計算時間の最適化を目指す
- デザインパターン等を理解し、目の前のワークロードを適切にモデリングし、コードに落とし込める
- フレームワークやIDEを使いこなして開発効率を高める
いずれも大事だけど、なんとなく1.の習得に時間がかかりそうだと思い、アルゴリズムに挑戦しようと思う。
そうなってくると必然目につくのが、競プロ(特にAtCoder)なわけだが、多くの解説がC++で書かれている。
ということで、C++の習得を最近は目指している。
やっていること
簡単な基礎の文法はUdemyの講座を一周流してみた。
pointerの理解は曖昧だが、まだ仕事で書くわけではないのでいったん放置。
で、今はけんちょんさんの本を勉強中。
備忘
で、ここからは本題だけど、ちょっとしたSyntaxとかでメモしておきたいことをここにメモしておく。
1. C++ 11を使う
C++のコンパイルをするときはg++コマンドを打っている。 xcodeとともにinstallされたg++だとversion11の公文(範囲loop, auto型など)は使えない。 (ちょっとこのへんのツールの理解は曖昧です)
対症療法的にですが、
$ g++ --std=c++11 <file/path>
で使用可能になった。
2. vectorいじり
pythonとかjsから入門した私からしたら、配列というのは言わずもがな可変長なのだが、CやC++の配列は定義時に長さを指定する必要がある。
そこで、vectorというSTLを使用する。 STLとはStandard Template Libraryの略で、 内部的にC++のTemplate構文(型を変数みたいに扱う)を使っていろんな局面で使えるようにしているLibraryのことである。
なお、あんまりvectorでは個別要素の操作は想定していないようである。
#include <vector> // STLの読込み vector<int> a; // aというvectorを定義 a.assign(50, -1) // 50の長さをvectorを初期値-1で初期化
Elasticserachでreindexを使ってみる
経緯
Elasticsearhのmappingsは追加はできても変更ができない。 変更したい場合は、indexを削除する必要がある。 でも、結構間違えたりするのでreindexでデータを退避したので その方法を書いておく
流れ
- reindexする元のsettingsとmappingsを使用して、reindex先のindexを作成
- reindexをする
- 適宜失敗データの対処をする
- reindex元のindexを削除
- reindex元に修正後のsettings, mappingsを作成
- 2.の逆方向のreindexをする
シナリオ
以下、サンプルコードを貼っていくが、
- reindex元のindex = original
- reindex先のindex = destination
って感じの前提でみてください。
1. reindexする元のsettingsとmappingsを使用して、reindex先のindexを作成
GET /original/_settings GET /original/_mapping PUT /destination/ { "settings": {}, "mapping": {} }
2. reindexをする
POST _reindex { "source": { "index": "destination" }, "dest": { "index": "original" } }
3. 適宜失敗データの対処をする
失敗データがレスポンスされるので適宜対処する
4. reindex元のindexを削除
DELETE /original
5. reindex元に修正後のsettings, mappingsを作成
適宜修正
- keyword型 => text型
- integer型 => keyword型
などの修正の場合はおそらくreindexで戻してくる時にエラーは出ないが、 それ以外の時は注意する。
6. 2.の逆方向のreindexをする
POST _reindex { "source": { "index": "original" }, "dest": { "index": "destination" } }
最後に
70万件程度のデータで180秒ほどの時間がかかった。 思ったよりも手軽にできそう。
Elasticsearchの親子関係のまとめ
概要
現在作成しているシステムにおいて、DBはDynamoDBを採用している。
DynamoDBのLSI, GSIの取り回しだけでは検索に限界があるので、
DynamoDBStream経由でElasticsearchにインデックスして、
Elasticesearchに検索を任せている。
Elasticsearchのドキュメントにリレーションを持たせないことがあるが、
よく内容を忘れるので備忘のためにこちらに記載しておきます。
シナリオ
- Company
- Employee
の2つのエティティがある。 全部kibanaで試すのを想定
Comapnyが親、Employeeが子
mappingsの定義
PUT /index/ { "mappings": { "properties": { "company": { "properties": { "name": { "type": "keyword" }, "years": { "type": "integer" } } }, "employee": { "properties": { "name": { "type": "keyword" }, "age": { "type": "integer" } } }, "company_employee_relation": { "type": "join", "relations": { "company": "employee" } } } } }
ポイント
- company_employee_relationは適当な名称でOK
- relationsの中は「 {親}:{子} 」にする。あとでdocを登録するときに使用する
データの登録
PUT /index/_bulk {"index": { "_id": "Company:001"}} { "company": {"name": "株式会社ソックス", "years": 80}, "company_employee_relation": "company"} {"index": { "_id": "Company:002"}} { "company": {"name": "キャップ工業株式会社", "years": 120}, "company_employee_relation": "company"} {"index": { "_id": "Company:003"}} { "company": {"name": "株式会社フーディー", "years": 30}, "company_employee_relation": "company"} {"index": { "_id": "Employee:001", "routing": "Company:001"}} { "employee": {"name": "武石徹", "age": 32}, "company_employee_relation": {"name": "employee", "parent": "Company:001"}} {"index": { "_id": "Employee:002", "routing": "Company:001"}} { "employee": {"name": "宮市武", "age": 30}, "company_employee_relation": {"name": "employee", "parent": "Company:001"}} {"index": { "_id": "Employee:003", "routing": "Company:003"}} { "employee": {"name": "相田宗介", "age": 31}, "company_employee_relation": {"name": "employee", "parent": "Company:003"}} {"index": { "_id": "Employee:004", "routing": "Company:002"}} { "employee": {"name": "田中仁", "age": 31}, "company_employee_relation": {"name": "employee", "parent": "Company:002"}}
ポイント
- 親を登録する時に以下を指定
- relation名(ここでいうと"company_employee_relation")
- 親の種類(ここでいうと"company")
- 子を入れる時に以下を指定
- relation名(ここでいうと"company_employee_relation")
- nameは子の種類(ここでいうと"employee")
- parentのindexを指定(ここでいうと"Company:00X")を指定する
- indexのroutingで親のindexを指定(親と同一shardsに入れるため)
クエリの例
以下のような感じで、{クエリ}という親/子をもつindexを検索という感じのクエリが可能
GET /index/_search { "query": { "has_parent": { "parent_type": "company", "query": { "wildcard": { "company.name": { "value": "株式会社*" } } } } } }
GET /index/_search { "query": { "has_child": { "type": "employee", "query": { "range": { "employee.age": { "gte": 31, "lte": 32 } } }, "inner_hits": {} } } }
所感
顧客のレガシーシステムをマイクロサービスな構成にマイグレーションする案件を受けることが多い。
お客様の頭はRDBMSな感じになっていることも多くて、そうなってくると結構リレーションの多い検索要件があったりする。
DynamoDBファーストチョイスで考えていると対応できないことも多いけど、
Elasticsearchを使うと結構器用に扱えるのいいなと思いました。
(あんまり日本語の字句解析とかElasticsearchっぽいことはあまりできていないけど...)
AWS Certified DevOps Engineer Professionalに合格しました
結果
AWS Certified DevOps Engineer Professionalに合格しました。 899点(合格点750点 / 満点1000点 )とでした。 今まで受けた他の認定も含めて最高点でした。
全ての問題を時終わるのに2時間35分。 見直し時間は25分ほどでした。
実務との関連
1. CI/CDパイプライン
普段から仕事ではCI/CDを使っています。ほとんどはボスが作ってくれますが、 私自身が作ることもしばしばでしたので CodePipelineを使用したデプロイについては 問題ない感じでした。
2. CDK
普段はCDKをつかってAWSリソースについて記述していますが、
CDKとはいえ当然クロススタックな参照等は使いますので、
そう言う意味ではCloudFormationについてはある程度いけました。
3. 実務では経験が薄かった部分
- SystemsManager
- Elastic Beanstalk
- ECS
- CodeDeploy
- AutoScaling
試験対策
1. 概要
試験の公式のドキュメントを見るのが一番ではありますが、個人としては、以下の様なポイントで意識してました。 1. 様々なアプリケーションのデプロイ方法を学ぶ 2. AMIとかDockerImageの変更の反映の仕方を学ぶ 3. セキュリティイベントをどうやって発生させるかを学ぶ
2. まずはデプロイ
基本的にはcloud formationをつかったデプロイが多いと思います。 あとは、Elastic Beanstalkとか、OpsWorksとかも軽くblackbelt読んで概要を学んでおきます。 それらを継続的にデプロイできる様にCode Deployの使用方法を学びます。
基本がわかったら、あとは以下の様なちょっとかわった要件への対応方法を学びます。
- パイプラインの中に手動承認アクションを入れる
- CodeCommitのブランチに準じたCode Pipelineを準備する
- オンプレのセキュリティチェックでコードをスキャンするステージを用意する
... などです。
いずれも模試や問題を解けばだいたいのパターンを掴めると思います。
3. 変更の反映
リソースの変更をどのように既存スタックに反映させるかも重要です。
- AMIを変更したので稼働中のAutoScaling内のEC2に反映する
- Docker Imageの変更を既存のタスクに反映する
などのシナリオです。
そのときにキャパシティの低下を許容するか、ダウンタイムを許容するかなどの要件を丁寧に問題文から読み解いて対応できる方法を考えます。
4. セキュリティイベントの発生
けっこう頻出だなと思ったのが以下の様なセキュリティイベントの検知と自動修復と言うパターンです
- 暗号化されていないElastic Block Storage
- IAMのアクセスキーの漏洩
- 低稼働なインスタンスの自動停止
...などです。
Config, Cloud Trail, Trusted Advisorなどでどのようにそういったセキュリティ項目を検知できるか、 検知したらどうやってイベントを発行できるかを整理しておくといいなと思いました。
5. ハイブリッド環境の運用
AWSとオンプレとのハイブリッドな環境の一元管理という文脈もけっこう出てきます。 大体以下の様なシナリオかなと思います。
- SSMエージェントを入れてSSMで一元管理
- CodeDeployのエージェントを入れてデプロイメントグループを設定してデプロイ
- CloudWatchエージェントをいれてログ吐き出し -> S3に集めてAthenaでアドホックに分析
などなど。
その他
前日に受けた模試では55%でしたので合格が危ぶまれたのですが、蓋をあけてみれば余裕の合格でした。
いちおう、Webエンジニアというロールで働いているので結構見覚えのある事項も多く比較的簡単に合格できました。
しかし、なぜこんなにもElasticBeasntalkってこのへんの試験で推されているのだろうか。。。
毎回謎である。
この調子で年内あと3つくらいスペシャリティ(セキュリティ、アレクサ、高度なネットワーク)とれたらこんなにうれしいことはないなぁ。
DatapipelineでDynamoDBを別アカウントのDynamoDBへデータ移行する
別アカウントへDynamoDBのデータをコピーしたい
MySQLだとdumpしたデータをexportしたり、RDSならスナップショット機能を使って、 別アカウントへのデータの移行は可能だと思います。 DynamoDBの場合はData Pipelineを使用するのがセオリーのようですが、 ちょっとハマったので記録を残しておきます。
目次
[1] 移行元アカウントでの作業
(1) 移行先のアカウントにS3バケットを作成して、バケットポリシーを設定する
クロスアカウントアクセスを許可するため、おおよそ以下の様な感じのバケットポリシーを設定します。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "DelegateS3Access", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::{{ 移行先のアカウントID }}:role/DataPipelineDefaultResourceRole" }, "Action": [ "s3:GetObject", "s3:PutObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::{{ 移行先のバケット名 }}/*", "arn:aws:s3:::{{ 移行先のバケット名 }}" ] } ] }
(2) データパイプラインの作成
基本的な手順は公式ドキュメントを参照していただければ問題ないかと思います。 ざっくり今回の設定したものを示すと以下の様な感じになります。
(3) データが大きい場合にPipelineがFAILEDになってしまう場合
DynamoDBの読込みのキャパシティユニットが不足していて読込に時間がかかりData Pipelineのタイムアウトにひっかかる
=> RCUを積んでおきましょうコアノードのメモリ不足 もともとデフォルトで設定されているインスタンスタイプが本日時点ではm3.large(2世代前)かつ1つとなっているので、 以下の様な感じでスケールアップかスケールアウトを考えてみる。
[2] 移行先アカウントでの作業
(1) DynamoDBデータのACLを変更
S3において、別アカウントがオブジェクトを作成した場合、そのオブジェクトの所有権は作成者にあります。 今回のDataPipelineは移行元のアカウントに作成しているので、DynamoDBのバックアップデータの所有権は 移行元アカウントになっています。 そのため移行先のアカウントでは設定はおろか閲覧もできない状態です。
まずは、バケットの所有者に権限を付与することをAWS CLIにて行います。
1.オブジェクトのACLを確認
aws s3api get-object-acl --bucket {{ bucket名 }} --key {{ オブジェクトのパス }} --profile {{移行元アカウントのプロフィール}}
2.オブジェクトに対して、バケット所有者に権限を付与するようにACLを変更
aws s3api put-object-acl --bucket {{ bucket名 }} --acl bucket-owner-full-control --key {{ オブジェクトのパス }} --profile {{移行元アカウントのプロフィール}}
今回は手でコマンド書いて対応できる範囲だったので1つ1つ対応しましたが、 数が多い場合はスクリプトを書いたり、もっと上手いやり方を考える必要がありそうです。
(2) DynamoDBへのimport
ここまでくれあばあとは公式ドキュメントをご参照ください。
[3] 所感
EMRについては試験対策でしか触れたことがない程度ですが、 マネコンをぽちぽちでけっこう手軽にDynamoDBのコピーができました。 少し設定をいじれば定期的な対応も可能な様なので使い道が結構ありそうですね。 少しでも誰かの役に立てば嬉しいです。
【エラー対処】"graphql/error/GraphQLError" has no exported member 'GraphQLError'. について
状況
aws/codebuild/standard:4.0イメージ で実施されているCodeBuild上で、
$ npm run build
した際に、以下のエラーが発生した。
macのlocal上では再現できず解決に手間取った。
[fatal] Nuxt build error ERROR in node_modules/@aws-amplify/api-graphql/lib-esm/types/index.d.ts ERROR in node_modules/@aws-amplify/api-graphql/lib-esm/types/index.d.ts(1,10): 1:10 Module '"graphql/error/GraphQLError"' has no exported member 'GraphQLError'. > 1 | import { GraphQLError } from 'graphql/error/GraphQLError'; | ^ 2 | import { DocumentNode } from 'graphql/language/ast'; 3 | export interface GraphQLOptions { 4 | query: string | DocumentNode; ╭─────────────────────────────╮ │ │ │ ✖ Nuxt Fatal Error │ │ │ │ Error: Nuxt build error │ │ │ ╰─────────────────────────────╯ npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! gyopro-frontend@1.0.0 build: `nuxt-ts build` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the gyopro-frontend@1.0.0 build script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! /root/.npm/_logs/2020-09-08T05_25_22_503Z-debug.log
環境
- Nuxt.js v.2.14.4
- Typescript
- CodeBuild > Image: aws/codebuild/standard:4.0
対処法
/vue-shim.d.tsに明示的にanyを追加してひとまずは回避した。
declare module 'graphql/error/GraphQLError' { export type GraphQLError = any }
雑感
本当に対象療法しか書けずに情けない。。。
仕事では別の人がフロントは書いていて、デプロイ時にエラーが発覚した時とか、
バックエンドAPIとの繋ぎ込みとかでちょっと手直しするだけなので、
率直にいうとTypescriptのことは全然わかっていません。。。
時間見つけてやらないとなとは思いつつ、 単純なTypscriptのSyntaxの読み物はけっこうあるんですが、 nuxtやvueとの絡みで学べるリソースが少ない(と私が誤解しているだけかも)のが 悩みどころ。。。
AWS Certified Solution Architect Professionalに合格しました
結果
AWS Certified Solution Architect Professionalに合格しました。 761点(合格点750点 / 満点1000点 )とでした。 あと1問間違えていたら落ちていました。。。 とはいえ合格は合格。一番効率的に合格したといえなくもないのでよしとします。
全ての問題を時終わるのに2時間45分。 見直し時間が15分ほどしかありませんでした。 文章が長くてしんどかった。
実務で勉強に役立ったこと
1. 普段の仕事
普段の仕事はサーバレスなシステム構築です。 なので、Lambda, DynamoDB, S3, Cloudfront, APIGW, SQSなんかは基本的には解けます。 CI/CDについても構築したりするのでその辺も解けました。 顧客アカウントの管理事務も担当しているので、Organizationsなんかも土地勘がありました。
2. ANGEL Dojo
AWS主催の擬似プロジェクトに参加した際に、500USDのクレジットが支給されたので、
それらを使ってAI系サービスをたくさん使ってました。
試験本番も深い問題はでないので何問か救われました。
3. コロナ対応
Workspaceのプロビジョニング
コロナ対応の際に、Workspacesを準備しました。 WorkspacesはADを立てるのがマストでその時にSimpleADを使ったので ついでに調べたのが役立ちました。 とはいえ、出題されるようなシナリオではないので、あくまで聞いたことあるって程度ですが。VPN接続
これもコロナ対応でいろいろやりました。 AWS VPN Clientを使って現在もたまに自社のシステムにアクセスするので 経験がありました。 とはいえ、試験のシナリオではDirectConnectのバックアップっていうのが多いので、 即刻役立つ感じではなかったですね。
ということで、これ以外は別個に試験対策をしました。
- いわゆるVPC系のアーキテクティング
- ネットワーク
- Cloudformationのクロスアカウント
試験対策
1. 対策本
最近リリースされました『AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説』なんかは3周くらい読みました。
あとは、「要点整理から攻略する『AWS認定 セキュリティ-専門知識』」なんかも読みました。 IAMやKMSなどちょっと苦手なところの解説が詳しいので、SAP試験にも大いに役立ちました。
試験シナリオについて詳細に解説されているので、大変勉強になりました。 不足部分はBlackbeltも読みましたが、実はそんなにしっかり読み込んでません。
それよりも概要をつかみたいなら、各リソースの「よくある質問」の方が大事かなと思います。 類似サービスとの使い分けなどについて触れられており、試験シナリオに即した記載も結構多くあります。
2. AWS Web問題集
AWS Web問題集 さんも活用させていただきました。 解説もコンパクトでわかりやすいですし、公式模試や実際の問題とドンピシャ同じものも多くて、 大変役立ちました。
その他
2日前に受けた公式模試の結果は60%でした。
2019年末に受けた時の結果が684点でしたので、「むしろ退化してるじゃん」ってなって落ち込みましたが、
受かったのでよかったです。
諦めないのが大切ですね。
また、前回よりも解ける問題が増えた分時間がギリギリでした。
集中力切らさないようにちゃんとお昼寝してからいってよかったです。
コロナ対策なんかしている時は、「俺は開発エンジニアなのに社内SEみたいなことさせやがって」と
不満たらたらでしたが、こうして試験対策には役立ってよかったです。
ジュニアレベルのエンジニアなんだからどんなことも嫌がらずやるべきですね。
今回の試験対策はおおよそ1ヶ月ほどでしょうか。
- 日々の実務のときに周辺事項もちゃんと調べておくこと
- 試験対策的にはちゃんと問題をたくさん解くこと
なんかが大切だなと思いました。