AWS Glueのワークフローを触ってみた

はじめに

この記事は「いのべこ夏休みアドベントカレンダー 2021」の10日目の記事です。
記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません(お約束)。

Glueってなんだ

まずは、公式サイトを一部引用しよう。 全文は、公式サイトを見てほしい。

AWS Glue は、分析、機械学習、アプリケーション開発のためのデータの検出、準備、結合を簡単に行える、サーバーレスデータ統合サービスです。 AWS Glue はデータ統合に必要なすべての機能を備えているため、数か月ではなく、数分でデータを分析し、使用可能にします。

AWS Glue(分析用データ抽出、変換、ロード (ETL) )| AWS

…。LEViAは文字を理解するのが苦手なようだ。さっぱり分からん。
ということで、絵を描いた。

f:id:levia9071:20210802101701p:plain
Workflowsを使ったGlueの流れ

いきなり手書きで恐縮だが、絵に描いた項目を軽く説明すると以下の通り。

名前 説明
Data Stores データの取得先
AWSサービスのS3,RDS,Redshift,DynamoDB、もしくはJDBC接続が利用可能
JDBC接続を使うことで、EC2内に立てたPostgresに接続することもできるゾ
Workflows CrawlersとJobsを結び付ける
Triggers Workflows内で作成。CrawlersもしくはJobsを実行させる"引き金"
Crawlers Data Storesからデータを取得し、MetadataTableに流し込む
Jobs MetadataTableからデータを取得・加工し、DataTargetに流し込む
Data Target データの吐き出し先。それ以上はDataStoresと同様の説明
Connection JDBC接続を行うために作成する「接続情報」
オンデマンド/
スケジューリング/
Lambda
実行方法の一例

実際にWorkflowsを作ってみるとしよう

作る処理としては、 CrawlersでS3に格納しているCSVを取得・MetaDataTableに吐き出しを行い、 JobsでMetaDataTableから取得・S3へCSVファイルを吐き出す。 データ加工はしないで右から左にデータを流すぞ。

■Crawlersの作成

作成した時の画面を1枚の画像にしてあるので、拡大してみてほしい。 URLなどは隠しているが、ご了承いただきたい。

f:id:levia9071:20210802144031p:plain
Crawler作成時の画面

画像No やること 今回の設定値
1 Crawlerを作成 Crawler名にdemoを指定
2 Crawlerの種類を指定 デフォルト
3 DataStoreの追加 今回はS3に置いてあるCSVファイルをインプットとする。
ディレクトリだけ隠せばよいものを手を抜いて全部隠してしまった
s3://~/demo_200mb.csvである。
4 DataStoreの追加 2つ目のDataStoreは使わないので、いいえを指定
5 IAMロールの選択 事前に作成したロールを指定
6 スケジュール設定 オンデマンドで実行
7 Crawlerの出力先 事前に作成しているGlueDataCatalog内のデータベース、testを選択
8 確認画面 完了を押下すればよい

[補足]IAMロール

事前に作成していたロールには、以下のポリシーを付与している。

  • AWSGlueServiceRole
  • S3バケットにアクセスするためのポリシー

[補足]GlueDataCatalog内のデータベース

コンソール画面開いて、「データカタログ>データベース>データベースの追加」で作成している。

f:id:levia9071:20210805184413p:plain
GlueDataCatalog内のデータベース

■Jobsの作成

Glue Studioで作成する。

1. Jobの新規作成

f:id:levia9071:20210804151716p:plain
Jobを新規作成

画像No やること 今回の設定値
1 SourceとTargetを選択して
Jobを新規作成する
SourceはAWS Glue Data Catalog
TargetはAmazon S3を選択
2 新規作成されたことを確認する ここでの操作はない。次に進む

2. Jobの詳細設定

f:id:levia9071:20210804152039p:plain
ジョブ詳細設定

画像No やること 今回の操作
1 Job detailsを表示する 上部タブ「Job details」を選択
2 Job名とIAMロールを選択 Job名は「demo」
IAMロールはCrawler同様「glue」
3 実行タイプなどの確認 値はデフォルトのまま。
「▶Advanced properties」を選択
4 [before]ScriptとLogの保存場所指定 設定前の画面
5 [after]ScriptとLogの保存場所指定 事前に用意したS3バケット内のディレクトリを指定
6 [before]Temporaryの保存場所指定 設定前の画面
7 [after]Temporaryの保存場所指定 事前に用意したS3バケット内のディレクトリを指定
8 接続情報やライブラリの指定 今回は不要なので、デフォルトのまま

3. Jobの処理を作る

データ加工したい場合は、ジョブの中で加工していくのだが今回はやらないゾー。

f:id:levia9071:20210804153446p:plain
Jobの処理を作る

画像No やること 今回の操作
1 [before]DataStoreを選択する 設定前の画面
2 [after]DataStoreを選択する Databaseは「test」
Tableは「demo_200mb_csv」を選択
3 DataMappingを設定する 流し込む際のデータ型を指定するが、今回はデフォルト。
4 [before]Targetを選択する 設定前の画面
5 [after]Targetを選択する Formatは「CSV」に変更
CompressionTypeは「None」 のまま
S3 Target Locationは事前に用意したS3バケット内のディレクトリを指定

■Workflowsの作成

・Workflowsの新規作成

f:id:levia9071:20210805181203p:plain
Workflowsの新規作成

画像No やること 今回の操作
1 Workflowsの画面を表示し、新規作成する AWSコンソールの右側「ワークフロー」を押下する。
「ワークフローの追加」を押下する
2 Workflowsの名前を決める 「demo」にした

・CrawlersとJobsを紐づける

f:id:levia9071:20210805181950p:plain
CrawlersとJobsを紐づける

画像No やること 今回の操作
1 Triggerを追加する 「トリガーを追加」を押下
2 Triggerを新規作成する タブ「新規作成」を押下
Trigger名に「demo_start」
TriggerTypeはオンデマンド
3 「demo_start」にCrawlersを紐づける 「ノード」を押下する
4 紐づけるCrawlersを選択する タブ「クローラ」を押下
「demo」を選択
5 Triggerを追加する Crawlersの右側にある「トリガーを追加」を押下
6 Triggerを新規作成する タブ「新規作成」を押下
Trigger名に「demo_event」
TriggerTypeはデフォルトのまま「イベント」
7 「demo_event」にJobsを紐づける 「ノード」を押下する
8 紐づけるJobsを選択する タブ「ジョブ」を押下
「demo」を選択
9 完成~~

・Workflowsの実行

f:id:levia9071:20210805182857p:plain
Workflowの実行

画像No やること 今回の操作
1 Workflowsを実行 実行したいWorkflowsを選択
「アクション>実行」を選択

さいごに

Glueは一歩踏み出すのに勇気が必要だったが、踏み出してしまえばこちらのもんだった。
Glue Studioという便利な機能もあるので、AWSを触れる環境にある人はぜひ遊んでみてもらいたい。

今回Crawlersを使って処理を行ってみたが、
Crawlersを使わずJobsだけでデータの取得・加工・吐き出しが可能だ。 え??その方が処理時間が短くなるじゃあないかって?
まったくもってその通りである。

以上。

qiita.com

【Android】AARをAzurePipelinesで作成したい

この記事は「いのべこ(富士通システムズウェブテクノロジー)Advent Calendar 2020」の6日目の記事です。
記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません(お約束)。

ゴール

ひとつのリポジトリという謎制約で、AzurePipelineを使ってAndroidのAPKとかAARを自動で作る

AzureDevOps

Projectを新しくつくって、きれいなAzureDevOpsを用意した。
あ、これprivateリポジトリです。publicにすればよかったとあとで気づいた。

f:id:levia9071:20201205203305p:plain

初回コミット

appというディレクトリとpartsというディレクトリの中に、それぞれのプロジェクトを格納しておく。
今回、appディレクトリではAPKを作成し、partsディレクトリではAARを作成する

f:id:levia9071:20201205203328p:plain ちなみにpartsディレクトリ配下には、partsというAndroidライブラリーモジュールを作成している。
ややこしい名前つけちゃったね

parts用のパイプラインを作る

f:id:levia9071:20201205203342p:plain

■ ゴール

partsモジュールをRelease用にビルドして、aarを作成。
作成したaarはパイプライン上のArtifactとして登録する。

■ ゴールのための手段

  1. root/pipeline-parts.ymlを作成する
  2. root/pipeline-parts.ymlをパイプラインとして登録する
  3. パイプラインを実行してみる

■ 詳細

1. root/pipeline-parts.ymlを作成する
ファイル名は分かりやすければ何でもよい。

# 対象
trigger:
  # ブランチ
  branches:
    include:
      - master
      - develop
  # ディレクトリ
  paths:
    # 対象
    include:
    - parts
    # 対象外
    exclude:
    - app
# このパイプラインで使う定数
variables:
  target_project: parts
  target_module: parts

stages:  
- stage: Release_parts
  # このstageの起動条件。masterブランチであれば、起動する。それ以外ならスキップする
  condition: eq(variables['Build.SourceBranch'], 'refs/heads/master')
  # AARを作るためのJobを組み立てる
  jobs:
  - job: Build_AAR
    pool:
      vmImage: 'vs2017-win2016'
    # このJobで使う定数
    variables:
      job_env: Release
      job_variant: Release

    steps:
    # gradlew :parts:assembleReleaseを実行してAARを作成するタスク
    # assembleReleaseの前にモジュール名を付けることで、特定のモジュールを指定する
    - task: Gradle@2
      displayName: 'gradlew :$(target_module):assemble$(job_variant)'
      inputs:
        gradleWrapperFile: '$(target_project)/gradlew'
        workingDirectory:  '$(target_project)'
        tasks: ':$(target_module):assemble$(job_variant)'
        publishJUnitResults: false
        jdkVersionOption: 1.8

    # 作ったAARを作業場所からArtifactにコピーするタスク
    - task: CopyFiles@2
      displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
      inputs:
        # コピー元
        SourceFolder: '$(system.defaultworkingdirectory)'
        # コピー対象
        Contents: '**/$(target_module)-release.aar'
        # コピー先
        TargetFolder: '$(build.artifactstagingdirectory)'
      condition: succeededOrFailed()

    # Pipeline上のArtifactとして登録するお作法タスク
    - task: PublishBuildArtifacts@1
      displayName: 'Publish Artifact: drop'
      inputs:
        PathtoPublish: '$(build.artifactstagingdirectory)'
      condition: succeededOrFailed()

2. root/pipeline-parts.ymlをパイプラインとして登録する
Pipeline>Create Pipeline>Azure Repos Git>「kotlin」>Existing Azure Pipelines YAML File
作成済みのYAMLを選べとポップアップが出てくるので、
masterブランチにあるpipeline-parts.ymlをパイプラインとして登録する。

3. パイプラインを実行してみる
Runを押すだけ!あら簡単

結果

作成したparts-release.aarはArtifactに登録されてる。成功!

f:id:levia9071:20201205203521p:plain

大分類 Java Kotlin
クラス - class Sample01 { } class Sample01 { }
コンストラク 引数なし public Sample01() { } init { }
コンストラク 引数あり public Sample(String str) { } init(str : String) { }
コンストラク 引数あり
※パターン2
- class Sample01(str : String) { }
メソッド 引数なし、戻り値なし public void test() { } public fun test() { }
メソッド 引数なし、戻り値なし
※パターン2
- fun test() { }
メソッド 引数あり、戻り値あり public String test(String str) { return str; } fun test(str : String) : String { return str }
インターフェース 宣言 public interface Sample() { } interface Sample() { }
インターフェース 実装 public class Sample01 implements Sample { } class Sample01 : Sample { }
継承 - public class Sample01 extends Sample { } class Sample01 : Sample { }
コンソール出力 改行あり System.out.println(""); println("")
コンソール出力 改行なし System.out.print(""); print("")
変数宣言 String(null) String str = null; str : String? = null

【Android】FirebaseCloudMessagingを使ってみた

お約束

この記事は「いのべこ夏休みアドベントカレンダー2020」の19日目(8月19日)の記事です。 本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません(お約束)。

本題

L●NEは、ユーザ側でアプリをタスクキルしていても通知が届く。 さて、どうやって実現するんだろう?という話。

クラウドメッセージという存在

Googleが出しているクラウドメッセージサービスがある。 2019年まではGCM(Google Cloud Messaging)だったが、2020年現在はFCM(Firebase Cloud Messaging)である。

Firebaseのサイトに沿ってプロジェクト情報の登録、アプリ情報(アプリ名とかパッケージ名)の登録をして。 アプリ実装側では、Firebaseでアプリ情報を登録してる間に生成されたJSONファイルを組み込んで。 SDKもbuild.gradleに追記しつつ、デバイストークンを取得。 取得したデバイストークン&登録したアプリのパッケージ名に向けて、通知を送信してやる流れ。

軽くやってみることにする。

Firebaseのサイトが1ステップごとに説明してくれるので、それにそってやれば大体できる。

ステップ Firebase/AndroidStudio やること
事前準備 Firebase コンソール画面にGoogleアカウントでログイン。
必要ならアカウント作って。
事前準備 AndroidStudio AndroidStudioを使い、アプリを新規作成する
アプリ名、パッケージ名はあとで使うので覚えておくこと。
プロジェクト登録 Firebase コンソールトップ画面から、プロジェクトを追加する。
プロジェクト登録 Firebase プロジェクト名をつける
プロジェクト登録 Firebase Googleアナリティクスを有効にするか否か選ぶ。
地域も選ぶ
今回はアナリティクスは有効。地域は日本にした。
プロジェクト登録 Firebase いろいろ同意するチェックを入れるとプロジェクトができる。
アプリ登録 Firebase プロジェクト作成後の画面で、作りたいアプリの種類を選ぶ。
今回はAndroid
アプリ登録 Firebase 先ほどAndroidStudioで作ったアプリのアプリ名・パッケージ名を入力する
アプリ登録 Firebase google-service.jsonが生成される。
このJSONファイルはapp配下にコピーする
アプリ登録 Firebase
&
AndroidStudio
[Firebase]google-service.jsonが生成される。
[AndroidStudio]このJSONファイルはapp配下にコピーする
アプリ登録 AndroidStudio [プロジェクトフォルダ]/build.gradleに依存関係を追加する。※ソース1
アプリ登録 AndroidStudio app/build.gradleに依存関係を追加する。※ソース2
実装 AndroidStudio バイストークンを取得し、画面に表示されるMainActivity.ktを作った。※ソース3
実装 AndroidStudio FirebaseMessagingServiceを継承したクラスを作る。※ソース4
実装 AndroidStudio AndroidManifestを修正。※ソース5
実装 AndroidStudio レイアウトをいじる。※ソース6
テスト AndroidStudio エミュレータを起動し、画面に表示されているデバイストークンをコピーしておく
テスト Firebase 左側メニューの「拡張>CloudMessaging>Send your First Message」を選ぶ | 
テスト Firebase 通知タイトル・内容を入力し、「テストメッセージを送信」を押下
テスト Firebase FCMトークンを入力して、送信を押す
テスト AndroidStudio エミュレータにインストールしたアプリに対して通知されてることを確認する

ね?簡単でしょ? Googleアカウント無料で作れるし、ぜひ遊んでみて!

いのべこ夏休みアドベントカレンダー2020では2本目。 また画面キャプチャとソースばかりの記事になってしまった。。 次回以降もこんな感じで、このお祭りに参加していきたい。

以下、ソースと画面キャプチャ

続きを読む

Androidアプリ「HelloWorld」を作って、好き勝手に弄ってみた

お約束

この記事は「いのべこ夏休みアドベントカレンダー2020」の16日目(8月16日分)の記事です。
本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません(お約束)。

きっかけ

Androidアプリ案件にかかわったので、せっかくならAndroid関係で何か書きたかった。

本記事でやること

  • プロジェクト新規作成
  • エミュレータの起動
  • ボタンを追加し、ボタン押下したら出力する文字列を変更する

準備

AndroidStudioのインストール

公式サイトに乗ってるから、その通りに。

AndroidStudioを日本語化

以下のQiita記事を見てください。
Android Studio日本語化

プロジェクト新規作成

・「新規AndroidStudioプロジェクトの開始」を押下する
・「空のアクティビティ」を選択して「次へ」を押下する
・プロジェクトの構成を入力する
 今回のアプリ名はHelloWorld。
  f:id:levia9071:20200810124635p:plain

f:id:levia9071:20200810124728p:plain

f:id:levia9071:20200810124813p:plain

f:id:levia9071:20200810130344p:plain

ポイントとなる箇所を確認する。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloworld">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!-- ★以下にボタンを追加する -->

</androidx.constraintlayout.widget.ConstraintLayout>

res/values/string.xml

<resources>
    <string name="app_name">HelloWorld</string>
</resources>

java/.../MainActivity.java

package com.example.helloworld

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    // ここら辺にボタン操作処理を記載する
    }
}

エミュレータを起動する

エミュレータを作る

f:id:levia9071:20200810175537p:plain

f:id:levia9071:20200810175557p:plain

f:id:levia9071:20200810175614p:plain

f:id:levia9071:20200810175641p:plain

f:id:levia9071:20200810175940p:plain

f:id:levia9071:20200810180009p:plain

さっきつくったエミュレータを選択して、起動する

「HelloWorld」を選んで、ツールバーの「▶」を押下すればエミュレーターが起動する。
f:id:levia9071:20200810180738p:plain

f:id:levia9071:20200812125817p:plain

ボタンを追加し、ボタン押下したら出力する文字列を変更する

ボタンを追加する(activity_main.xml

UI画面からボタンを追加する

①UI画面の「パレット>Common>Button」をドラック&ドロップ
②追加したボタンを「右クリック>制約」を選んでいき、「親の上部」と「親の開始」を定義する。
 ※①の時に「ボタン位置を定義せよ」とエラーが出るが②をやれば解決する。
③画面右側の「属性」からボタンidを定義する。今回は「button」

f:id:levia9071:20200813134251p:plain f:id:levia9071:20200813145044p:plain

xmlでごりごり書いてボタンを追加する

<!-- 以下を追加する -->
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="164dp"
        android:layout_marginTop="271dp"
        android:text="Button"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

テキストビューにidを付与する

ボタンを押下するときにテキストビューの値を変えるために、idを付与する。
テキストビューをタップし、画面右側の属性からidを付与する。
今回はtextView f:id:levia9071:20200813145447p:plain

ボタン操作処理を作る(MainActivity.kt)

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // ここら辺にボタン操作処理を記載する
        findViewById<Button>(R.id.button).setOnClickListener {
            textView.text = "Hello"
        }
    }

JDKでとやかく言われるとき

f:id:levia9071:20200810180522p:plain

f:id:levia9071:20200810180536p:plain

リクエストヘッダーをカスタムして、Webviewで投げつけたい

はじめに

タイトルの通り。
リクエストヘッダーをカスタムして、Webviewで表示させるウェブブラウザにぶん投げたい。

オンラインもくもく会議での進捗報告を兼ねています。

Kotlinでやりたいこと

  • Webview
    • カスタムヘッダー投げつける
  • Azure認証情報取得して、カスタムヘッダに追加する
  • マッシュルーム電卓(あどかれに投稿予定)

今日の目標

  • Webview
    • カスタムヘッダー投げつける

環境

  • AndroidStudio
  • Android 10.0(API29)

苦戦したところ

メイン部分

class WebView : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        WebView.setWebContentsDebuggingEnabled(true)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_web_view)

        val myWebView = findViewById<WebView>(R.id.webview)

        val extraHeaders: MutableMap<String, String> = HashMap()
        extraHeaders["ORIGINAL_HEADER"] = "original data"

        val url = "https://uchy.me/tools/request_headers.html"  // ★HTTPリクエストヘッダー表示ツール
        myWebView.loadUrl(url, extraHeaders)
    }
}

今回作ったソース

kotlin/webview · master · F LEViA / hatenaBlog · GitLab

参考URL

developer.android.com matbluecat.hatenablog.com

Angularで遊んでみる2

続き。

「Demoです」だけを表示させたい。

src/index.htmlを弄った

app-rootをコメントアウトして、demo-rootを記載しておく。

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>MyApp</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <!--<app-root></app-root>-->
  <demo-root></demo-root>
</body>
</html>

src配下にdemoを作る

  • demo.component.css
  • demo.component.html
  • demo.component.ts
  • demo.module.ts

demo.component.html

<h1>{{ title }}</h1>

demo.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'demo-root',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.css']
})
export class DemoComponent {
  title = 'Demoです';
}
````

### demo.module.ts

import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core';

import { DemoComponent } from './demo.component';

@NgModule({ declarations: [ DemoComponent ], imports: [ BrowserModule ], providers: [], bootstrap: [DemoComponent] }) export class DemoModule { }

## 実行
[f:id:levia9071:20200629175716p:plain]
---

# 生成されたディレクトリの役割について
|ディレクトリ名|役割|
|:--|:--|
|src|ソースコードを置く。よく使う|
|src/app|アプリケーションのソースコードを置く|
|src/assets|画像などの静的ファイルを置く|
|src/environments|開発環境と本番環境などの環境ごとに変動させたい値を格納するファイル(application.ymlみたいなやつ)を置く。|
|e2e|e2e(end to end) テスト(実際にブラウザを動かしてページのテストを行うもの)のコードを置く。src/test配下みたいなイメージ|
|node_modules|nodeのモジュールが置かれるディレクトリ。基本的には触らない。libs配下?|

## src/app配下のファイルについて

|ファイル名|役割|
|:--|:--|
|src/app/app.component.ts|ロジック。`.ts`とは、Typescript コードを示す拡張子である|
|src/app/app.component.html|表示|
|src/app/app.component.css|スタイル|