TECH PLAY

株式会社カケハシ

株式会社カケハシ の技術ブログ

381

こんにちは、カケハシのデータ基盤チームで開発ディレクターをしている松田です。最近、歳のせいか疲れが溜まりやすくなっており、毎週サウナに通っています。 カケハシでは今までRedashを利用して全社にデータ提供をしていましたが、去年の7月からDatabricksを利用することになりました。そのため、今までRedashで使っていたクエリやダッシュボードをDatabricksへ移行する必要がありました。 その時に、Redash(Presto)とDatabricksのデータベース操作言語(DML)違いで少しハマり、みなさんにも同じ轍を踏んで欲しくないため、本記事では変更点や対応方法をまとめたいと思います。是非、チートシート的な使い方をしてくれると泣いて喜びます! Redash時代の構成とPrestoについて Databricks導入以前のアーキテクチャイメージは以下になっていました。 データ利活用観点だと、RedashからAthenaでS3を参照して分析したり、そのクエリ結果から CTAS で中間データをを作成していました。Athenaでは、DMLとしてPrestoというオープンソースを利用しているため、基本的にはPrestoのドキュメントを参照しています。 Presto は、大量なデータに対してインタラクティブな分析クエリを実行するための高性能分散型SQLクエリエンジンです。 Facebookが自社の大規模なデータセットに対して、インタラクティブに結果を返すことを目的として2012年に開発され、2013年にオープンソースとなったものです。 主に「一秒〜数分程度で終わる集計」や「コンパクトな処理を素早く実行したい場合」などに利用されるアーキテクチャとなります。 Databricks時代の構成とDatabricks SQLについて 現在のDatabricks導入後のアーキテクチャイメージは以下になります。 Databricksは、Redashとほぼ同じ様な見た目や使い勝手になっており、SQLクエリ、ビジュアライズ、ダッシュボードなどが利用できます。 Databricks SQLでDelta Lakeを参照してデータ分析したり、中間データを作成したりしています。 Databricks SQL は、Databricks Lakehouse Platformに組み込まれたエンタープライズデータウェアハウスとしてなります。 Databricks SQLのコア機能は、 SQLウェアハウス と呼ばれる最適化されたコンピューティングです。 Databricksは、Hadoopのオルタナティブとなるプロダクトを開発するためにカリフォルニア大学バークレイ校の研究室仲間で2013年に立ち上がりました。そのHadoopのオルタナティブとなるプロダクトとして開発されたのがSparkで、そのSparkを使ったクラウドサービスが「Databricks Cloud」となっています。そのため、Databricksのドキュメントでは多くの場合はSpark SQLを使用してSQLクエリと機能を説明しています。 そして、Spark SQLはDatabricks SQLを使用して作成されたクエリをサポートします。 つまり、Redash側はPresto、Databricks側はDatabricks SQL(≒ Spark SQL)で、Spark SQL自体はHiveQLと似ておりHiveの関数と互換性があります。 それらの構文の違いでハマったポイントを説明します。 DMLの違いによりハマったところ 基礎関数(配列、結合、変換) ARRAYの記述が異なる 配列を作りたい時に使用する。 Databricks SQLでは () を使い、Prestoでは [] を使う。 -- Databricks(Databricks SQL) SELECT ARRAY("a", "b"); -- 結果: ["a", "b"] -- Redash(Presto) SELECT ARRAY["a", "b"]; -- 結果: ["a", "b"] LATERAL VIEW explode / CROSS JOIN UNNEST Array型のカラムに保存されている値を行へ展開するする時に使います。 例では、患者さん1レコードに対して複数の疾患をArray型で持っている場合、疾患毎にレコードが展開されます。 -- Databricks(Databricks SQL) SELECT patient.name, disease FROM patients LATERAL VIEW explode(diseases) AS disease; -- Redash(Presto) SELECT patient.name, disease FROM patients CROSS JOIN UNNEST(diseases) AS t(disease); バッククォート / ダブルクォート AS句で日本語を利用する時は、Databricks SQLではバッククォートで囲み、Prestoではダブルクォートで囲む必要があります。 -- Databricks(Databricks SQL) SELECT '日本語' AS `日本語`; -- Redash(Presto) SELECT '日本語' AS "日本語"; Hash関数の型が異なる SHA256でHash化する時に使います。 Prestoの方はSHA256関数の引数と返り値がbinaryのため、型変換の関数が必要になる。 -- Databricks(Databricks SQL) SELECT SHA2('patient_id', 256) -- Redash(Presto) SELECT TO_HEX(SHA256(TO_UTF8('patient_id'))) varcharをcastする時のLength Parameterの有無 型変換のcast関数を使う時にDatabricks SQLはLength Parameterを指定する必要がある。 -- Databricks(Databricks SQL) cast(created_at as varchar(10)) -- Redash(Presto) cast(created_at as varchar) try_cast / try 無効なCASTが発生した際に、クエリを正常終了してNULLを返して欲しい時に使用する。 Databricks SQLでは型に厳しくないため利用の機会が少ないが、Prestoでは利用するシーンはよくあります。 Prestoの try では、CAST以外にもゼロ除算や数値範囲外も検知できる。 -- Databricks(Databricks SQL) SELECT try_cast('10' AS INT); -- 結果: 10 SELECT try_cast('a' AS INT); -- 結果: NULL -- Redash(Presto) SELECT try('10' AS INT); -- 結果: 10 SELECT try('a' AS INT); -- 結果: NULL 日付関数 datediff / date_diff 2つの日付の期間を計算したい時に使います。 Prestoでは引数に day 以外にも month などを選択できますが、Databricks SQLでは選択できないため日数の差分しか取得できません。 また、引数の順番が異なるためご注意ください。 -- Databricks(Databricks SQL) SELECT datediff('2023-02-09', '2023-02-07') --結果: 2 -- Redash(Presto) SELECT date_diff('day', CAST('2023-02-07' AS DATE), CAST('2023-02-09' AS DATE)) --結果: 2 TIMESTAMPDIFF / TIMESTAMP_DIFF 2つのタイムスタンプの期間を計算したい時に使います。 引数の順番が異なるためご注意ください。 -- Databricks(Databricks SQL) TIMESTAMPDIFF(MINUTE, c.time_created, d.time_created) --結果: 0, -- Redash(Presto) TIMESTAMP_DIFF(d.time_created, c.time_created, MINUTE) -- 結果: 0, date_addの引数指定が異なる 日付の足し引き計算をしたい時に使います。 Prestoでは引数に day 以外にも month などを選択できますが、Databricks SQLでは選択できません。 そのため、月の足し引き計算は add_months で代替します。 -- Databricks(Databricks SQL) date_add('2023-02-09', -1) -- 結果: '2023-02-08' -- Redash(Presto) date_add('day', -1, CAST('2023-02-09' AS DATE)) -- 結果: '2023-02-08' DATE_FORMATの時刻形式が異なる タイムスタンプ型の日時を日付文字列へ変換する時に使います。 時刻形式のフォーマットに差異があります。 -- Databricks(Databricks SQL) DATE_FORMAT('2023-02-09 11:22:33', 'yyyy-MM-dd') -- 結果: '2023-02-09' -- Redash(Presto) DATE_FORMAT('2023-02-09 11:22:33', '%Y-%m-%d') -- 結果: '2023-02-09' to_date / from_iso8601_date 文字列から日付へ変換する時に使います。 -- Databricks(Databricks SQL) to_date('2023-02-09') -- 結果: '2023-02-09' -- Redash(Presto) from_iso8601_date('2023-02-09') -- 結果: '2023-02-09' date_trunc / TIMESTANP_TRUC タイムスタンプを指定した日付や時刻のところで切り捨てる時に使います。 引数の順番が異なるためご注意ください。 -- Databricks(Databricks SQL) date_trunc('day', '2023-02-09 11:22:33') -- 結果: '2023-02-09' -- Redash(Presto) TIMESTAMP_TRUNC('2023-02-09 11:22:33', DAY) -- 結果: '2023-02-09' 集計関数 percentile / percentile_cont INT型のグループ内で中央値、第一四分位数などを取得する時に使用する。 例では、 0.5 に設定することで中央値を取得している。 -- Databricks(Databricks SQL) SELECT percentile(col, 0.5) FROM VALUES (0), (10) AS tab(col); -- 結果: 5 -- Redash(Presto) SELECT percentile_cont(col, 0.5) FROM (VALUES(0),(10)) t(col); -- 結果:5 row_numberでorder byを指定する必要がある 行に番号をふる時に使用する。 Databricks SQLでは ORDER BY を指定して上げる必要がある。 -- Databricks(Databricks SQL) ROW_NUMBER() over(PARTITION BY count ORDER BY count), -- Redash(Presto) ROW_NUMBER() over(PARTITION BY count), max_by, min_byの複数返却指定ができないため、指定した要素の値を取得する際にはarray_aggとfilterを利用する必要がある group by を使用した時に、第2引数で指定したカラムの最大・最小の第2引数を取得したい時に使用する。 Prestoでは第3引数に返却個数を指定して配列で取得できるが、Databricks SQLでは値しか取得できない。 そのため、Databricks SQLを利用する場合は、 group by で1番目の値ではなく、2番目の値を取得するには少し書き換えが必要になります。 -- group by でまとめられる対象のレコード -- date, name, rank -- "2023-01-01","A",1 -- "2023-01-01","B",2 -- Databricks(Databricks SQL) SELECT min_by(name, rank) as first_rank_name -- 結果: "A" SELECT array_agg(name) filter(where rank = 2)[0] as second_rank_name -- 結果: "B" -- Redash(Presto) SELECT min_by(name, rank) as first_rank_name -- 結果: "A" SELECT element_at(min_by(name, rank, 2), 2) as second_rank_name -- 結果: "B" まとめ RedashからDatabricksへ移行した際にDMLでハマったポイントとその解決方法をご紹介しました。 まだ、文法の違いで詰まることはあるとは思いますが定期的に情報をアップデートしていき、社内や社外の人に知見を共有できたらとと考えています。 もし少しでも興味を持った方がいらっしゃいましたら、データエンジニアとしてカケハシで一緒に働きませんか? 一緒に有数のデータカンパニーを目指せていければと思い、仲間を募集しております。
みなさんは、技術とは何か、考えたことはあるでしょうか。 ここでは、技術哲学の立場から考えるための参考として、ハイデガーの技術論を取り上げます。 技術論のタイプ A.フィーンバーグの技術: クリティカル・セオリーの分類によれば、 これまでの技術論は2つの立場に分けることができる、と考えられています。 道具説 自立的存在説 道具説は、世の中に広く受け入れられている見方で、 技術とは「中立的」であり、利用者の目的に奉仕する道具と考えます。 逆に、技術の中立性を否定する見方として、自立的存在説という見方もあります。 この説では、技術とはそれ自体が社会のすべてを管理の対象物として作り変えようとする、と考…
AWSコストをいますぐ最適化しませんか? キャッシュフロー、ユニットエコノミクス、改善しませんか? この記事では、とにかくいますぐなんとかしたい方向けの方法を金額面で大きい傾向にあるサービスごとに26個紹介します。 以下各見出し内の💰はコスト削減度、⚡はおまけでパフォーマンス改善度を指します。 (1) 💰💰💰 CloudWatch Logs: とにかくログを出さないこと、まとめること AWS料金のうち、CloudWatch Logsが上位を占める傾向にあります。保存期間が無期限だから費用がかかる...と見せかけて、実際はログ出力自体の料金が大半です。 レガシーWebアプリケーションのログは1リクエストにつき何回も何行も出力する傾向があります。フレームワーク特有の不要なログも付いてきます。勝手に出力されるログは放置せず整理して、リクエスト単位でイベントとしてまとめましょう。 参考記事 各種ジョブもログが多いですね。 特定のエラーに対するログが出しっぱなしなら、エラーを修正をするかログのほうを消しましょう。 Lambda実行時に必ず出るCloudWatch Logsの話 Lambda実行のたびにCloudWatch LogsにSTART / REPORT / ENDの3行が必ず出力されます。 このログはメトリクスを兼任していますが、あえてここの出力も削りたいなら、LambdaからCloudwatch LogsへのPUT権限を外すという大技があります。 Proxy的な、実行量が多いが何もしない処理にはありかもしれません。 Lambda パフォーマンス改善 ≒ コスト改善です。パフォーマンスチューニングの観点は別稿に譲るとして、ポイントだけ解説します。 以下も参考にしてください。 (2) 💰💰⚡ Lambda: ARM化する 単純に20%落とせます。Node.jsはARM化しやすいものの、Pythonは利用ライブラリによっては工数がかかります。 (3) 💰⚡ Lambda: handlerの外で初期化する Lambda実行のたびに初期化処理が実行されていることがあります。今一度確認しましょう。 (4) 💰 Lambda: Provisioned Concurrencyを削減する 本番環境でもLambda実行料金以上にかかっている事例が散見されます。精査しましょう。 (5) 💰 Lambda: ランタイムのバージョンを上げる 最近のプログラミング言語はパフォーマンスに気を使っています。 2023年2月現在ではまだ未対応ですが、Python 3.11はFaster CPythonプロジェクトにより高速化されていますし、 boto3 1.20.32からのkeepalive機能 にも期待したいところです。 (6) 💰⚡ Lambda: Node.jsでのTCP Keep-alive追加 Lambda公式ドキュメントにもあるとおりです。なお、Node.js 18やAWS SDK for JavaScript v3、CDKのNodejsFunctionでは設定済みなので対応不要です。 (7) 💰⚡ Lambda: Preflight Requestに対応する クラウド時代、アプリケーションまでOPTIONSメソッドが到達したら何かがおかしいでしょう。ルーティングをアプリではなくクラウドインフラに全部任せることをおすすめしています。API GatewayやCloudFrontなどのインフラで対応しましょう。 Access-Control-Max-Ageによるキャッシュも大事です。もちろんPreflight Requestが発行されないことが理想です。 (8) 💰⚡ Lambda: とにかく実行しないようにする 実行しなければ無料!コード負債もゼロ!ついでに障害もゼロ! 以下のような方法が考えられます。 EventBridgeで直接外部APIを実行する Event Filteringで除外処理をLambdaの外に置く Lambda経由でのS3アクセスを避ける API Gatewayの固定レスポンスを活用する DynamoDB 特にGSI関係がコストが嵩む要因です。 以下の記事も参考にしてください (9) 💰💰 DynamoDB:GSIの不要な射影を減らす なんとなく全部を射影にしてしまいがちですが、特に書き込みコストに跳ねるので控えましょう。新しい同一のテーブルにも複製して書き込むイメージです。 (10) 💰⚡⚡ DynamoDB: batchでget/writeする たまにgetを連打するコードを見かけます。batchに書き換えてアクセスをまとめ、節約しましょう。 (11) 💰 DynamoDB: 保存する属性名、キー名を短くする NoSQLであり型が決まっていない以上、レスポンス内で属性名やキー名を繰り返すコストが膨大になります。少しでも削りましょう。アプリケーションコード側でわかりやすい属性名にマッピングすると可読性とコスト、パフォーマンスを両立できます。 (12) 💰 DynamoDB: On-Demandにする キャパシティをProvisionedにすると使っていない時間帯も料金が固定でかかります。ワークロードが1日を通して大きく動くならOn-Demandのほうが無難です。 一方リザーブドキャパシティによる事前予約を考えるとProvisionedも選択肢に上がりますね。 AWS Config Advanced Queryを使えば、キャパシティ種類を全テーブル全アカウント分一覧化できます。 Aurora RDS いかにスペックを下げるか、負荷ピークを作らないかが勝負です。 (13) 💰💰 Aurora: インスタンスファミリーを最新化にする 2023年現在最新のr系インスタンスはr6gです。新しいバージョンが登場したときにスムーズにアップグレードする体制が整っているでしょうか? (14) 💰💰⚡⚡ Aurora: インデックスを付与する 残念ながらテーブル作成時にインデックスを付与していない事例が散見されます。インデックスがないとDB負荷があがり、インスタンスサイズ増、料金増につながります。MySQLなら複合インデックスの理解が浅めの方が多めです。複合インデックスが1テーブルにおおよそ1つはないと不安を感じます。APMツールで確認しながらインデックスを追加しましょう (15) 💰💰⚡ Aurora: N+1クエリを放置しない DB負荷が大きく上がりますし、処理時間がかかることでアプリケーションレイヤーのコストもかかります。APMツールを入れているとモニタリングコストも大きくかかります。 (16) 💰💰 NAT Gateway: S3 / DynamoDBのGateway endpointを設定する VPC内からNAT Gatewayを通さずにアクセスできます。NAT Gatewayの通信量が多いときは確認してみましょう。移行時のリスクはほぼありません。 (17) 💰 NAT Gateway: 通信量を減らす アプリケーション起動時にイメージ取得や外部のリポジトリアクセスによる通信が時折発生します。キャッシュ可能ならキャッシュするか、インターフェイスエンドポイントでNAT Gatewayの迂回を検討しましょう。特にFargate + ECRが危険です。 (18) 💰💰💰 S3: バージョニングの再検討 AWSのベストプラクティスにもある通り、セキュリティや運用上はオブジェクトの過去バージョンを保持したいところです。一方、過去のオブジェクトをそのまま保持するため膨大な料金がかかります。 バージョニングの停止のほか、過去バージョンのストレージクラスを変更する、過去バージョンの世代数やTTLを設定するといった選択肢があります。 (19) 💰💰💰 S3: バージョニングの残骸を確実に消す 検討の結果バージョニングを停止しても、以前のバージョンは残ったままです。新しいバージョンの生成を停止しただけなので。過去バージョンが不要なら消去する必要があります。 S3 Storage Lensを使うとアカウント単位で旧バージョンの総サイズを確認できて便利です。 (20) 💰⚡ S3: list APIよりS3インベントリを使う 詳しく見るとListObjects APIが嵩んでいることが見受けられます。S3インベントリを駆使し、毎回listしなくてよくなるか検討してみましょう。 (21) 💰⚡ API Gateway:Authorizerのttlキャッシュを設定する 認可処理は呼び出し回数が多くなります。キャッシュしましょう (22) API Gateway: gzip化する たまに設定できていないので確認しましょう。圧縮サイズを設定するとonになる仕組みです。 (23) API Gateway: 固定レスポンスを活用する バックエンドAPI呼び出しが不要ならこちらを。 (24) Glue: 既存記事をご確認ください パフォーマンスはコストということで、カケハシでGlueを主力にしているチームの記事を参考にしてください 以下の記事も非常に参考になり、なにかあるたびに勧めています。ありがとうございます🥰 (25) KMS: マネージドキー+暗号化に注意 AWS所有のキー以外を利用すると、料金が大幅に上昇します。KMS自体もかかりますが、CloudTrailの費用が膨大になります。 (26) 💰💰💰⚡⚡⚡ とにかく不要なアクセスを減らす 一番最初にやることをおすすめしますが、若干時間がかかるので最後に持ってきました。 そのフロントエンドからバックエンドの通信は本当に必要ですか? すでにあるキャッシュ機構は使えませんか?新しく導入するのは大変ですが既存なら現実的 ポーリング、リフレッシュの間隔を延長できませんか? フロントエンドのような前段側で改善すれば、後段側の料金も減るのでおすすめです。 参考記事 最後に この記事ではすぐに成果を出したい人向けに比較的簡単な方法を解説しました。開発環境やRI/契約といった原価改善の本質からそれる話は除いています。 前回の記事では、サーバレスの優位性について説明しており、 次回は根本的にコスト構造を変化させる方法について記載する予定です。 文責:高木
こんにちは、株式会社カケハシでおくすり連絡帳 Pocket Musubiの開発を担当している渡辺です。 今回は文字コードについての記事を書きました。 Pocket Musubiではお薬手帳用QRコードを読み込み、デコードした結果を利用します。ここでデコードするときにうまくいかないケースがあり、そこでの知見です。 文字コードについて 蛇足ですが、文字コードについて簡単におさらいします。 文字コードとは、文字をコンピューターで扱うために、文字ごと割り当てた数字のことです。 文字コードの対応表に基づいて、文字を数字に割り当てることを文字エンコードと言います。 文字コードの対応表には、ASCIIやUT…
はじめに こんにちは。カケハシの患者リスト開発チームの金と申します。 患者リストはWEB業務アプリとして、薬局から患者さんへのフォローで関係性を向上させるためのツールです! 患者リスト開発チームではDDDとClean Architectureを基にしてスクラム開発を行なっています。 私はこのチームに入って半年で、患者リスト開発チームに入る前まではDDDとClean Architectureに関してあまり知識がない人でした。 この半年DDDに関して学んだり気づいたことが多いですが、その中で、ユビキタス言語とドメインについて少々考えたことを記述してみたいと思います。 DDD初心者目線の記事になりま…
はじめに こんにちは、LINE上で動くおくすり連絡帳 Pocket Musubi というサービスを開発している種岡です。 ある日チーム内メンバーから CI実行時間がとても長くなり困っている というアラートが発せられました。 実際に確認しに行くと、開発初期の頃は5分ぐらいだったテストが、いつの間にか 20分 以上にもなっていました。 待ち時間は、DX体験を損なうだけでなく、本来できたはずである付加価値を生む開発時間を奪う側面も持ち合わせており、即刻対処すべき案件と捉えテストを早くするタスクに取り掛かりました。 結果、当サービス比ではありますが、3倍ほど早くすることができました。 そこで備忘録がて…
はじめに こんにちは。 Musubi の機能開発チームでフロントエンドを主に担当しております、井上です。どうぞよろしくお願い致します。 カケハシではスクラムによる開発を推進しており、その運用はあるていど各チームの裁量に任されています。 今回は私が所属しておりますチームがスクラムを運用をしていく中で使用している GitHub Projects について触れていきます。   どうぞお付き合いのほど、よろしくお願い致します。 ご注意 上記でも触れておりますが、本記事における GitHub Projects の運用は Musubi の機能開発チームにスコープしたものです カケハシ全体で GitHub Projects を用いたスクラム運用を行っているものではありません GitHub Projects とは GitHub が提供するプロジェクト運用のためのツールです。 ドキュメント では次の記載があります。 (公式ドキュメントから引用) Projects は、GitHub での作業を計画および追跡するための、適応性のある柔軟なツールです。 日々の業務を行うなかで発生する「作業のチケット化」「作業状況」「検討結果やメモ」といった動きや情報を、この GitHub Projects を使って共有しています。 なぜ GitHub Projects なのか もともとは Trello を使ってタスク管理を行っていました。 Trello でもチケットドリブンによる開発タスクの管理を行えていましたが、次の点を実現したいという欲求がありました。 スプリントを設定したい GitHub とのシームレスな連携が行いたい ベロシティを計測したい 進捗状況を視覚化させたい チームの透明性を確保したい これらの解決にあたり、 JIRA や ZenHub も選択肢に挙がったのですが 追加費用が発生することなく利用開始できる 求める機能がまぁまぁ揃っていた この 2 点から GitHub Projects の利用を決めました。 まず 1. ですが、 GitHub Projects は利用しているプラン上で利用できます。利用にあたり追加で料金が発生することはありません。 次に 2. について。 Insights という機能を用いて分析情報を視覚化することができます。また GitHub から提供されているので、 Issue と PR の連携もスムーズに行えます。 どう運用しているか では実際にスプリントを回すにあたり、どのように運用( 利用 )しているかについて触れていきます。 1. Custom fields の設定 画面右側の 「...」 から 「Settings」 を開き Custom fields を設定していきます。 ( 画像上部の棒線は個人アイコンを隠すため ) Estimate の設定例. Sprint の設定例. これは Iteration を指定しているので、対象となるアイテムを追加していくことが出来ます。 この画面からそれぞれ設定していくのですが、デフォルトで用意されているフィールドだけで足りない場合は + New field から追加します。( ↑ の画面はすでに後述のフィールドを追加した状態です ) なお Field type は一度設定すると変更できないようですのでご注意ください。誤って Field type を設定した場合はフィールド名の右にある 「...」 から Delete field で削除し、再度作成します。 ちなみに、現在は次のフィールドを設けて運用しております。 フィールド 内容 備考 Status チケットの状態を表します かんばん方式で Issue を見る際に各ステータスにチケットが配置されます Estimate チケットの作業ポイントを表します Function チケットが受け持つ機能を表します チケットが実現する機能ではなく Web App, API といった大きな括りでの機能を設定します Epic チケットが実現する内容を包括的に管理する項目です 後述の「残念な部分」でも取り上げますが, Epic としてチケットを発行できないのでフィールドで管理しようという試みです Type チケットが Epic なのか実作業としての Task なのかを区別します Sprint チケット対応を行うスプリントを表します 後述の Insights で分析する際に重要です Remarks チケットがプランニング時に対応予定となっていたものかどうかを表します こちらも Insights で分析する際に重要です ここで設定した項目を実際の Issue 作成時に埋めていきます。 そしてその内容が後述の Issue 管理にも影響します。 2. チケット管理 チケットは GitHub Projects の Add item から作成すると便利です。 作成直後はチケットが Draft 状態で配置されます。その後、チケットの詳細を埋めていく中で適切なリポジトリを選択して Issue にコンバートします。 追加したいステータス上で Add item を押します チケットタイトルを入力します 1. で選択していたステータス上に Draft でチケットが配置されました チケットを開いて詳細を記入していきます( Issue へのコンバートもここで行います ) 枠で囲った Edit からは OverView が編集できます。 その右側の枠で囲った項目からは、先述の Custom fields に対して情報を設定していきます。 Convert to issue で Draft から Issue にコンバートされます。このとき、 Issue を配置するリポジトリを選択します。 3. Issue 管理 Issue 管理は目的に応じて「かんばん方式」か「テーブル方式」が選択できます。 現在は主に次の 3つ のビューを用意して Issue の進捗状況の確認に役立てています。 目的 方式 俯瞰して確認 かんばん方式 スプリント単位で確認 テーブル方式 担当者単位で確認 テーブル方式 かんばん方式 ステータスごとに「列」が配置され、チケットはそのステータスに応じた列に配置されます 各チケットの状況が一目で分かるので状況の把握に役立ちます テーブル方式 前掲の Custom fields で設定したフィールドで グルーピング することで、フィールド単位のチケット把握に役立ちます 私達の運用では上記表のとおり スプリント と 担当者 単位の把握に利用しています 4. ワークフロー 簡素・単純ではありますが、Issue や PR の状況に応じたワークフローも利用できます。 現在用意されているワークフローは Item added to project Item reopened Item closed Code changed requested Code review approved Pull request merged Auto-archive items (Beta) があります。 これらは各ステータスに応じたワークフローで、Issue か PR, またはその両方が ( When ) 指定されたステータスになったとき ( Set ) どうするか 程度の設定しかできません。 また任意でワークフローを追加することはできないようです。より柔軟なワークフローを運用したい場合は GitHub Actions の利用が必要になります。 というわけで、いまのところ Item added to project Item closed Code changed requested Pull request merged の 4つ のワークフローでシンプルに 「チケット追加」「チケット終了」「PR発行・レビュー依頼」 「PR マージ」 時にチケットを指定のステータスに移動させる運用としています。 5. 分析 さて、GtiHub Projects を利用する最大のメリットである 分析 です。 GitHub Porjects では Insgihts という機能から作業状況の分析が行なえます。 次のチャートを作成してスプリントの振り返りに活用してしています。 目的 要約 説明 スプリントの作業状況を確認 各ステータスの積み上げを折れ線グラフで分析 ( バーンアップチャート ) ポイントを プランニング時, 差し込み, トータル でそれぞれ分析する スプリントの作業量を確認 消化ポイントを棒グラフで分析 ( ベロシティ ) スプリント単位で計測し、1スプリントあたりに消化できるポイントを把握する Epic ごとのポイントを確認 Epic の積み上げを棒グラフで分析 Epic の割合を把握する スプリントの作業状況を確認( バーンアップチャート ) スプリントの作業量を確認( ベロシティ ) Epic ごとのポイントを確認 ( 塗りつぶしていますが、各 Epic に対応するポイントを出力してます ) 6. チームの透明性の確保 ここまでに触れてきた内容がそのまま「チームの透明性の確保」につながるのですが、 メンバ各人が何をやっているのか 対応している案件はどの程度進んでいるのか トラブルが発生していないか、もしくはトラブルになりそうな気配はないか 等々... こうした「チーム・メンバの置かれた状況を相互に理解しやすくする環境づくり」ということを「透明性」という言葉で表しておりまして、その実現が GitHub Projects の運用を通して期待する効果の一つなのですが、実際にその効果は少しずつ見えてきました。 次は一例ですが、 疑問 スプリント中にプランニングで決めた作業( ポイント )の消化が低いのはなぜか 原因 プランニング外の割り込み作業が発生している 単にそのタスクを担当しているメンバの進捗が遅れている 対策 割り込み作業に対して ベロシティを計測することでスプリント辺りのポイントから予め割り込み作業分を確保しておく もしくは割り込み作業を次スプリントに回せないかの調整をする 個人の進捗遅れについて ペアプログラミングやモブプログラミングを通じて遅れとなっている原因の解決に臨む という具合に、疑問・課題に対するアクションを取りやすくなりました。 この辺はチケット発行して対応にあたるという、タスクをチケット化しただけの運用では得られなかった効果であると思いますので、導入の意義が充分にあったといえる点です。 番外. Issue と PR の紐付け GitHub Projects の利用目的の一つが Isseu と PR の連携でした。 とはいっても、GitHub Projects を利用して特別な何かをすることはありません。 公式のドキュメント Pull RequestをIssueにリンクする に従い PR を作成することで両者を紐付けます。 ただこれだけの作業ですが、これによって GitHub Porjects 上で Issue と PR を見ることができるのは日々の業務を行う上でかなり便利になります。 残念な部分 バーンダウンチャートが利用できない Epic チケットが発行できない 1. バーンダウンチャートが利用できない GitHub Projects ではバーンダウンチャート機能はまだ提供されていないようです。 こちら のように GitHub Projects からデータを取得して自前でバーンダウンチャートを作成することもできるようですが、そこにコストをかけることは目的から外れますので対応していません。 いまのところは前掲のようにバーンアップチャートで代替していますが、 スプリント単位でのポイント消化 という点においては視覚化できております。 バーンダウンチャートについては今後の GitHub Projects のアップデートに期待したいところですね。 2. Epic が発行できない チケットを Epic として発行できない のが GitHub 導入当初は歯がゆいと感じておりました。 とはいえ、前掲したように現在は「Custom fields に Epic を設定」することで運用できております。 むしろ Epic チケットを発行しなくても現在の運用で「どの案件に紐づくチケットは把握できる」 Epic チケットに Issue チケットを紐付ける作業のほうが面倒ではないか という向きもあり、Epic チケットは無いままでも良いかな、という感じで回っています。 今後のアップデートで Epic チケットについても提供されるかもしれませんが、そのときにまた改めて使用するかを検討したいと思います。 まとめにかえて まとめにかえて、というところで GitHub Projects を使ってみての所感を述べたいと思います。 ここまで簡単ではありますが、ざっと GitHub Projects での運用について触れて来ました。内容の繰り返しにはなりますが、改めて GitHub Projects を採用したことで良かった点について挙げていきます。( 残念な点については前項で触れたので割愛します ) 良かった点 スプリントを設定できる スプリントにおける進捗状況や作業分析を視覚的に訴えることができる Issue と PR の紐付けが簡単できる 上記に関連して Issue や PR との UI/UX の乖離がない ワークフローによるステータスの自動変更 チームの透明性の確保 上記は課題として解決したいと思っていたことですが、これらは GitHub Projects を導入することで解決できました。 そのなかでも、やはりスプリントの状況を視覚化できたというのは大きな点です。 作業状況がグラフとして見えるというのは直感的に理解しやすいということでモチベーションの向上に繋がります。もちろん進捗が悪いときも如実に反映されるので落ち込むこともありますが、そこは反省点として振り返り次のスプリントに臨む、という切っ掛けにもなります。 また先の項目( 6. チームの透明性の確保 )にて触れましたとおり、作業状況の相互理解を進めたいという目的の元に、トラブルの早期発見・早期解決に向けた対策の実施、というメリットが得られました。 もうひとつ触れておきたいと思います。 GitHub Projects, Issue, PR といずれも GitHub で提供されているものなので、これらの連携がスムーズに行えるというのは狙いの一つではありました。 が、 UI/UX が統一された( Issue や PR との UI/UX の乖離がない )点は意図していないメリットでした。 感覚的な話になってしまいますが、UI/UX が統一されたことで、チケット管理の際のストレスが個人的には軽減されたと感じております。 特に意識したこともなかったのですが PR は GitHub, Issue は別のツールで管理 と、見た目や操作感といった部分で大きな違いがあるというのは意外とストレスになるのだということに気付かされました。今後、またツールを選定するようなときには要件として頭の片隅に置いておこうと思った点です。 少し話が逸れました。そろそろまとめに入ります。 繰り返しになりますが、解決したいと思っていた課題は概ね対応できました。 残念な点で挙げたようにちょっと物足りないなという面はあります。ですがそれらは ( 今のところは ) 運用でカバーできていることもあり、取り立てて問題視するほどのものではありません。 スプリントを運用するにあたり、「まず何かツールを使ってみたい」とか「導入コストをかけたくない」といったときに GitHub Projects は良い選択肢となるのでは、と思います。 ZenHub や JIRA といった有料の管理ツールを使用する前の管理ツールの入門的な意図で使ってみるというのも良いのではないでしょうか。 参考 Projects を使用した計画と追跡 ランキング参加中 プログラミング
初めまして、カケハシのデータ基盤チームでデータエンジニアをしている伊藤と申します。 最近の悩みは、二郎ラーメンを食べていないのに「二郎ラーメンの匂い(臭い?)がする」と同居人に言われることです。私のニュースは置いといて、カケハシでは全社的なデータ活用基盤のプラットフォームとしてDatabricksを採用してから半年以上経過しました。 Databricksを導入してから今まではバッチ処理しかしてませんでしたが、最近になってAutoLoaderを利用してストリーム処理をするようになりました。その対象として、弊社が提供している薬歴システムのMusubiの監査ログを扱ったので紹介させて頂きます。 Au…
お金は好きですか? コストを削減したいみなさん、ようこそ。 原価を低減したいみなさん、ようこそ。 サーバレスのビジネスでの優位性は多数ありますが、今回はその中でもコスト最適化の面から説明します。 やればやるだけ成果が見える: 努力が必ず報われる物語 レイテンシを1ms削るようなリリースができたとしましょう。(ネットワーク系のコストは同等と仮定します) 従来の開発では、CPUやメモリ利用量が若干減った程度では、コストは変わりませんでした。利用率が100%にならないようバッファを持たせており、多少削ってもサーバーの台数削減につながらないからです。あえてリソースを減らすとしても、利用率100%のリス…
初めまして、カケハシのデータ基盤チームでデータエンジニアをしている伊藤と申します。 最近の悩みは、二郎ラーメンを食べていないのに「二郎ラーメンの匂い(臭い?)がする」と同居人に言われることです。私のニュースは置いといて、カケハシでは 全社的なデータ活用基盤のプラットフォームとしてDatabricksを採用し てから半年以上経過しました。 Databricksを導入してから今まではバッチ処理しかしてませんでしたが、最近になってAutoLoaderを利用してストリーム処理をするようになりました。その対象として、弊社が提供している薬歴システムのMusubiの監査ログを扱ったので紹介させて頂きます。 AutoLoaderとは Databricks上で特別な設定無しで、クラウドストレージに到着した新しいデータを段階的かつ効率的にDelta Lakeに取り込む仕組みです。AutoLoaderにはディレクトリごとに数百万のファイルにまで拡張できるスケーラビリティの対応や導入が容易で使いやすいといったメリットがあります。 以前、spark streamingでストリーム処理を行い、Delta Lakeに取り込んた際の課題として、読み込み対象のスキーマが想定外に更新されてデータ取得によく失敗していました。AutoLoaderにはスキーマの変更が起きた際に通知を行い、無視するか失われるデータを救助できる仕組みがあるため、その課題を解決できます。 AutoLoaderの動作原理 AutoLoaderでは新規ファイルを検知するために ディレクトリ一覧モード と ファイル通知モード があります。 本記事で紹介する事例では、Kinesis Firehoseを使用してファイルを日付順にアップロードしており、ディレクトリ一覧モードでAutoLoaderを起動し、API呼び出し数を削減しております。 アーキテクチャ Musubiの監査ログはCloudWatchに出力されています。AWSのKinesisを利用してCloudWatchからJSONデータをS3に格納しています。AutoLoaderで監査ログを処理する前は、日次でバッチ処理を行っていたので以下のようなアーキテクチャとなっていました。 最近になって監査ログデータのリアルタイム性が求められてきました。今までのアーキテクチャだとデータ抽出まではリアルタイムになっていたのですが、Databricksに読み込む際にバッチ処理をしていたため、利用者にとってはリアルタイム性に欠けていました。そのためアーキテクチャの見直しを行い、日次バッチからAutoLoaderで処理を行うよう変更しました。 Databricksでは、増分データの取り込みにはDelta Live Tables(DLT)でAutoLoaderを使用することが推奨されていますが、Unity Catalog/DLTの統合は本記事執筆時点の2023年1月31日時点ではサポートされていないため、現時点ではDelta Live Tablesを使用していません。 AutoLoaderでJSONファイルの読み込み 以下を実行することでS3に到着するJSONが順次処理されるストリームが起動します。 df = spark.readStream.format( "cloudFiles" ) \ .option( "cloudFiles.format" , "json" ) \ .option( "cloudFiles.schemaLocation" , "checkpointに使用するpath" ) \ .option( "cloudFiles.schemaHints" , "type string, target string, action string, year string, month string, day string, hour string) \ .option(" cloudFiles.partitionColumns ", " year,month,day,ho ur") \ .option(" cloudFiles.useIncrementalListing ", True) \ .option(" lineSep ", " \n ") \ .load(" 取り込みデータのpath ") .format("cloudFiles") と指定することでAutoLoaderを利用しています。\ .option("cloudFiles.schemaLocation") にチェックポイントディレクトリを指定することで、AutoLoaderがどこまでファイルを処理したか記録しています。\ 予めスキーマ情報がわかっていたので .option("cloudFiles.schemaHints" にカラム名と型を指定することでスキーマ情報を強制させています。\ Kinesisで順次パーティション区切りでストリーミングデータが送られてくるので、 .option("cloudFiles.partitionColumns") に年/月/日/時を指定しています。\ AutoLoaderの動作原理で触れましたがディレクトリ一覧のモードを使用しており、日付順でS3にファイルがアップロードされるため、 .option("cloudFiles.useIncrementalListing", True) を指定して、ディレクトリ一を完全に一覧するのではなく、インクリメンタルな一覧を適用することにより新規ファイルを検知するのに必要なAPI呼び出し数を削減しています。\ .option("lineSep) には二つの連続するJSONレコードの区切り文字として\nを指定しています。 Databricks Unity Catalogに書き込み 以下を実行することで読み込んだストリームをDatabricksのUnity Catalogに書き込みます。 df = spark.writeStream.format( "delta" ) \ .option( "checkpointLocation" , "checkpointに使用するpath" ) \ .outputMode( "append" ) \ .option( "mergeSchema" , "true" ) \ .partitionBy( "year" , "month" , "day" , "hour" ) \ .trigger(processingTime= "1 minutes" ) \ .toTable( "unity catalogに保存するテーブル名" ) .option("mergeSchema", "true") で新規カラムが追加された場合に自動でDeltaに取り込むようオプション指定しています。\ .trigger(processingTime="1 minutes") に1 minutesを指定することで、1分間隔でJSONを順次処理しています。 JSONファイル処理部分で躓いた ストリーミングでデータを処理すると、スキーマの予期しない変更や取り込み対象ファイルのデータが不正といった様々な要因でエラーに遭遇するかと思います。今回AutoLoaderでJSONファイルを処理する際に以下のエラーに遭遇しました。 org.apache.spark.sql.catalyst.util.UnknownFieldException: Encountered unknown field(s) during parsing: {} 上記のエラー原因は、データスキーマ変更が要因でない場合、データの中に空のJSONが存在すること起因の不具合によるものです。対処方法としては、以下2パターンのどちらかになるかと思います。 取り込み対象データの空のJSONを削除する エラー後、AutoLoaderを再実行 今回はAutoLoaderを再実行することで問題なくデータを取り込むことができて、データ利用者に最新の情報を提供することができました。 まとめ 以上、DatabricksのAutoLoaderを紹介させて頂きました。簡単にセットアップができて最新の情報をいち早くデータ利用者に届けられる仕組みは大変素敵なものだと実感しました。 本記事ではDelta Live Tablesについて触れませんでしたが、Unity Catalog/Delta Live Tablesの統合が正式版となった暁には社内でDelta Live Tables(DLT)でAutoLoaderを使用する動きが加速するかと思います。 一緒に手を動かしてデータ基盤構築しませんか。少しでも興味を持ってくださった方がいらっしゃれば以下からご応募お待ちしております。
KAKEHASHI でバックエンドエンジニアをしている横田です。 私が運用している Web サービスでは、AWS Glue で ETL 処理をしたデータを Aurora MySQL に投入することでユーザーが利用できるようにしています。 その中でも「データを Aurora MySQL に投入する」方法に関して、今まで色々なパターンを試してきました。 AWS Glue の Job で作成したデータを Aurora に投入するいくつかのパターンとそのメリット・デメリットについて紹介できればと思います。 Aurora MySQL にロードする 3 つのパターン データを MySQL に insert…
はいさい!カケハシの新米メンバー、オースティンと申します。 沖縄から参上しております! 概要 RxJS の mergeMap と switchMap の違いと使い方について解説します。 背景 Observable を使っていると、必ず直面する問題があります。それは、 複数の Observable をどうやって一緒に実行できるか 、という問題です。 とある Observable の処理が終わった後に、そのデータを元に、別の Observable でさらに非同期処理をすることは開発者として多々あります。 Promise の then でまた別の Promise を返してチェーンしていくのと同じことです。 しかし、RxJS では、 Promise と違って Observable を直列にチェーンするのに使う pipe の OperatorFunction が複数存在します。代表的なのは、 mergeMap 、 mergeWith 、および switchMap です。 なぜ RxJS には複数のチェーン手法が存在するのか この疑問は湧きませんか? この疑問に答えるためにはまず、 Observable と Promise はどう異なるのか考える必要があります。 筆者に言わせれば、 Observable の最も大きな違いは、 未解決の Observable の処理を取り消す、つまり止めることが簡単にできる点 でしょう。 Promise では、 Promise が解決してもその中で実行された処理を取り消す方法がありません。以下のコードを見ましょう。 const promise = new Promise((resolve) => { let count = 0; setInterval(() => console.log( `Loading ${++count} seconds.` ), 1000); setTimeout(resolve, 5000); } ); promise.then(() => console.log( "Resolved!!" )); 読者は読んでお分かりかと思いますが、このコードを実行してみると、以下のように、 Promise が解決された後でも、ログが出続けるのです。 同じ例を Observable で書きます。 import { Observable } from "rxjs" ; const observable$ = new Observable((observer) => { let count = 0; const interval = setInterval(() => console.log( `Loading ${++count} seconds.` ), 1000); setTimeout(() => { observer.next( "Timeout ended." ); observer.complete(); } , 5000); return () => clearInterval(interval); } ); observable$.subscribe( { next: console.log, complete: () => console.log( "Completed!" ) } ); Observable の executor 関数が、戻り値としてその interval をクリアする関数を返すのですが、これが Observable が解決(complete)された時に呼ばれるのです。 すると、 Promise と違って永遠に続く interval が残されません。 この 後片付け の機能が、 Observable の非常に優れたところなのです 。 そして、本記事につながる部分ですが、この後片付けがあるからこそ、 Observable をチェーンする時の手法が用途によって異なるのです。 mergeMap とは何か mergeMap は、map と似ていますが、簡単にいうと、一つの Oberservable から流れたデータを違う Observable に流すチェーン OperatorFunction なのです。 以下の例を見てみましょう。 import { fromEvent, scan, mergeMap, interval, takeWhile, tap, combineLatest, of } from "rxjs" ; const docClick$ = fromEvent( document , "click" ); const clickCount$ = docClick$.pipe( scan((acc) => acc + 1, 0), tap((count) => console.log( `Document was clicked ${count} time(s).` )) ); clickCount$ .pipe( mergeMap((clickCount) => { const intervalPerClickCount = [ of(clickCount), interval(500).pipe(takeWhile((i) => i < 5)) ] ; return combineLatest(intervalPerClickCount); } ) ) .subscribe(( [ clickCount, i ] ) => console.log( `mergeMap: Click no ${clickCount} , interval count: ${i} ` )); document をクリックすると、クリックした回数をまず clickCount$ で足し算します。 それから、 mergeMap を使って新しい Observable を返します。 その新しい Observable は、 combineLatest で合わせた二つの Observable 、 of(clickCount) と interval です。 要するに、 mergeMap で Observable<number> を Observable<[number, number]> というふうに変えています。 試してみる document を一回クリックすると以下のように出力されます。 Document was clicked 1 time(s). mergeMap: Click no 1, interval count: 0 mergeMap: Click no 1, interval count: 1 mergeMap: Click no 1, interval count: 2 mergeMap: Click no 1, interval count: 3 mergeMap: Click no 1, interval count: 4 document を 2 回連発でクリックすると以下のようにログが出力されます。 Document was clicked 1 time(s). Document was clicked 2 time(s). mergeMap: Click no 1, interval count: 0 mergeMap: Click no 2, interval count: 0 mergeMap: Click no 1, interval count: 1 mergeMap: Click no 2, interval count: 1 mergeMap: Click no 1, interval count: 2 mergeMap: Click no 2, interval count: 2 mergeMap: Click no 1, interval count: 3 mergeMap: Click no 2, interval count: 3 mergeMap: Click no 1, interval count: 4 mergeMap: Click no 2, interval count: 4 ここで重要な観察ですが、 2 回目のクリックがあっても、1 回目のクリックを元にした combineLatest の Observable<[number, number]> は最後まで続くのだ という結果を記憶に留めておきましょう。 switchMap switchMap は mergeMap と同じように、上流の Observable を新しい Observable に合わせます。 しかし、重要な違いがあります。 switchMap は、上流の最も最新も値をのみとって、下流の新しい Observable に流すのです 。 たとえ、以前の値に基づいて流した下流の Observable がまだ解決されていないとしても、 それらの Observable を止めるのです 。 上記のソースコードで mergeMap が使われていたところを switchMap にしてみましょう。 clickCount$ .pipe( switchMap((clickCount) => { const intervalPerClickCount = [ of(clickCount), interval(500).pipe(takeWhile((i) => i < 5)) ] ; return combineLatest(intervalPerClickCount); } ) ) .subscribe(( [ clickCount, i ] ) => console.log( `switchMap: Click no ${clickCount} , interval count: ${i} ` )); これも実験してみましょう! 試してみる 1 回だけクリックしてみる Document was clicked 1 time(s). switchMap: Click no 1, interval count: 0 switchMap: Click no 1, interval count: 1 switchMap: Click no 1, interval count: 2 switchMap: Click no 1, interval count: 3 switchMap: Click no 1, interval count: 4 mergeMap と同じ結果です。 2 回連発してクリックしてみる Document was clicked 1 time(s). Document was clicked 2 time(s). switchMap: Click no 2, interval count: 0 switchMap: Click no 2, interval count: 1 switchMap: Click no 2, interval count: 2 switchMap: Click no 2, interval count: 3 switchMap: Click no 2, interval count: 4 なるほど!**最後のクリックだけ、5 回の interval が出たのです! まとめ ここまで mergeMap と switchMap の違いを解説してきましたが、いかがでしょうか? 似たような効果があるのに、歴然な違いがあるので、筆者は知った時に驚きました。 この違いを知らずにコードを書いていると、解せないエラーが起きそうな気がします。 たとえば、HTTP リクエストでクリックに対してログを記録させたい時に、どれを使えばいいと思いますか? ビジネスモデルにもよるのですが、 switchMap だと、ログのリクエストがまだ終わっていないのに、ユーザーがまたクリックすると、前のログのリクエストがキャンセルされ、 最後のクリックだけがログに残る結果になるのです 。なので、 mergeMap が向いているでしょう。 逆に、自動推測などだと、最新の値だけに対してリクエストを投げたいはずなので、 mergeMap より switchMap が適しているのではないでしょうか? RxJS は奥深くて強力なのですが、強力だからこそ誤った使い方をすると痛い目に遭うなと思っています。 どんどん理解を深めていきましょう!
こんにちは!カケハシにて薬局と患者の関係性を向上させるためのツールである 患者リスト というWEB業務アプリケーションを開発している小室と申します。 本プロダクトのフロントエンドの開発環境としては、React + esbuildを採用しており、採用の経緯や実践している環境構築方法などは以下の通り、TechPlayやQiitaなどに記事を投稿してきました。 TechPlay: 新規事業プロダクト開発時の技術選定どうやった? スライド Qiita: esbuild + React(TS) で実現する超軽量な開発環境 しかしながら、esbuildは標準でsassに対応しておらず、今までの環境ではCS…
こちらの記事は、カケハシ Advent Calendar 2022の25日目の記事になります。 こんにちは、四番隊隊長とは声が低いこと以外何一つ共通点がないCTOの海老原です。 すみません、タイトルは釣りタイトルです。何故こんな釣りをアドベントカレンダーのラストに持ってきたかですが…しばしばスタートアップの経営陣の最大のミッション・役割の一つとして採用が挙げられますが、ご多分に漏れず私も日常の時間のかなり多くの部分をソフトウェアエンジニアやデザイナー、プロダクトマネージャーのような開発系職種のカジュアル面談での事業説明やオファー面談に割いています。 その中でよく候補者の方からご質問を頂くわけで…
こちらの記事はDatabricks Advent Calendar 2022の25日目の記事になります。 こんにちは、カケハシでMusubi Insightという薬局向けBIツールのバックエンドエンジニアをしている高田と申します。 BIツールを開発しているということもあり日常的にETL処理の実装を行っていますが、普段の開発ではAWS Glueを採用しています。 しかし、カケハシでは全社的なデータ活用基盤のプラットフォームとしてDatabricksが採用されたこともあり、とあるプロジェクトでDatabricksを活用してデータエンジニアやデータアナリストとうまく協業できたので、その時の事例を紹介…
こちらの記事はDatabricks Advent Calendar 2022の24日目の記事です。 はじめに 初めまして。カケハシでデータサイエンティストをしている赤池です。 弊社はフルリモートで業務できるため今年9月から地元の仙台市で業務していますが、本格的な冬の到来を前に戦々恐々しています。(寒い。雪。路面凍結。) さて、あなたは「Pandas API on Spark」を知っていますか? これは「pandasと同じ書き方でSpark上で処理を実行できる」という代物で、pandasでは処理に時間がかかる or そもそも扱えないような大規模データを、ほとんどpandasと同じ感覚で処理できる…
この記事は、カケハシ Advent Calendar 2022 の 24 日目 の記事になります。 こんにちは、木村です。(@kimutyam) 医薬品発注管理最適化領域の新規事業のテックリード兼エリアPO、プラットフォームドメイン全体のアーキテクト、データ基盤チームのアーキテクトサポートの3つを兼務しているエンジニアです。直近はプラットフォームドメインの領域のテナント管理の立ち上げに集中をしています。 プラットフォームドメインとは カケハシはMusubiを始めとした5つのサービスを提供しています。これらは独立して価値を届けられる単位ではありますが、サービスを横断してしなやかなユーザー体験を提…
こちらの記事はDatabricks Advent Calendar 2022の23日目の記事です。 はじめに 初めまして。カケハシにてデータサイエンティストをしている赤池です。 業種的に、自己紹介の際に統計学のビッグネームとの関係性を聞かれることがたまにありますが全く関係ありません。統計学もがんばります。 突然ですが、あなたの分析環境では「DBから抽出したデータをPythonやRなどで利用する際にうまく連携できていない」なんてことはありませんか? そして「この処理だけはRでやりたいが、そのためだけに別環境を開きたくない」なんて思うことはありませんか? このブログでは、データサイエンティストの立…
こちらの記事はDatabricks Advent Calendar 2022の23日目の記事です。 カケハシのデータ基盤チームの松田です。カケハシでは今年の7月からDatabricksを利用しており、そろそろ半年ぐらい経とうとしています。Databricksを採用した背景については、以下の記事に詳細をまとめていますので、まだ拝見されていない方は見ていただければ幸いです。色々な人から「とても参考になった!」と反響を呼んでいるオススメの記事です! 今回はDatabricks導入のタイミングで、データの閲覧権限とその管理者について見直したので、その検討過程と現時点での方針についての投稿になっています…
KAKEHASHI でテックリードをしている横田です。 KAKEHASHI に入社して早 5 年が経ちまして、色々な経緯から社内勉強会の運営をしてきました。 その中で感じた社内勉強会による共有知の有用性について、紹介させていただきたいと思います KAKEHASHI の勉強会について KAKEHASHI 社内では、エンジニア・非エンジニアに限らずさまざまな勉強会が立ち上がり、チームをまたがって学習する文化があります。 例えば、今まで私が参加した勉強会には以下のようなものがありました。 技術 Web API の設計 輪読会 ドメイン駆動設計 勉強会 実践的データ基盤への処方箋 輪読会 データ基盤勉…