INSERT SELECTやCREATE TABLE ASでWITH句を使う時の注意点

こんにちは、エニグモ 嘉松です。

BUYMAのプロモーションやマーケティングを担当している事業部に所属しており、その中のデータ活用推進室という部署で会社のデータ活用の推進やマーケティング・オートメーションツール(MAツール)を活用した販促支援、CRMなどを担当しています。

さて、SELECT文で得た結果のデータを(そのまま、直接)テーブルに挿入する INSERT SELECT や、SELECT文で得た結果からテーブルを作成して更にデータまで挿入するCREATE TABLE ASは何かと便利な機能(文法、技?)ですが、WITH句(SELECT文による結果を一時的に名前を付けてテーブルのように利用する便利な機能(文法、技?))と併用、一緒に利用しようとした時に、ちょっとした注意点があるので備忘録として記載しておきたいと思います。

例えば、以下のようなにWITH句で複数の(仮想的な)テーブルを定義して、それらを結合(JOIN)して結果を得るようなSQLがあったとします。(サンプルなのでとてもシンプルなSQLにしていますが、通常では WITH句を使う場合はもっと複雑なSQLになることが多いと思います。)

※以下のSQLはBigQueryで検証していますので、他のDBMSでは異なる結果やエラーになる場合があることをご了承ください。

WITH
emp AS (

SELECT
7369 AS empno,
'SMITH' AS ename,
20 AS deptno,

UNION ALL

SELECT
7499 AS empno,
'ALLEN' AS ename,
10 AS deptno,

UNION ALL

SELECT
7521 AS empno,
'WARD' AS ename,
30 AS deptno,
),

dept AS (

SELECT
10 AS deptno,
'DEVELOPMENT' AS dname,
'MAYNARD' AS loc

UNION ALL

SELECT
20 AS deptno,
'SALES' AS dname,
'HOUSTON' AS loc

UNION ALL

SELECT
30 AS deptno,
'RESEARCH' AS dname,
'PALO ALTO' AS loc
)

SELECT

e.empno,
e.ename,
e.deptno,
d.dname,
d.loc

FROM emp e
JOIN dept d ON e.deptno = d.deptno
;

このSQLの結果は以下のようになります。

empno ename deptno dname loc
7369 SMITH 20 SALES HOUSTON
7499 ALLEN 10 DEVELOPMENT MAYNARD
7521 WARD 30 RESEARCH PALO ALTO

このSQLの結果をINSERT SELECTでテーブルに挿入しようとした時に、うっかり以下のようなSQLを書くとエラーになります。

WITH
emp AS (

SELECT
7369 AS empno,
'SMITH' AS ename,
20 AS deptno,

UNION ALL

SELECT
7499 AS empno,
'ALLEN' AS ename,
10 AS deptno,

UNION ALL

SELECT
7521 AS empno,
'WARD' AS ename,
30 AS deptno,
),

dept AS (

SELECT
10 AS deptno,
'DEVELOPMENT' AS dname,
'MAYNARD' AS loc

UNION ALL

SELECT
20 AS deptno,
'SALES' AS dname,
'HOUSTON' AS loc

UNION ALL

SELECT
30 AS deptno,
'RESEARCH' AS dname,
'PALO ALTO' AS loc
)

INSERT dataset.emp_dept -- 最終的な結果を得るSELECTの直前に記載

SELECT

e.empno,
e.ename,
e.deptno,
d.dname,
d.loc

FROM emp e
JOIN dept d ON e.deptno = d.deptno
;

BigQueryでは以下のようなメッセージが表示されます。

Syntax error: Unexpected keyword INSERT at [39:1]

最終的に結果を得るSELECT文の前に INSERTを記載するという、ごく自然な、直感的な、あたかも正しそうな方法ですが、エラーとなります。

正しくは、以下のようにWITH句の前にINSERTを記載する必要があります。

INSERT dataset.emp_dept -- WITH句の前にを記載する必要がある

WITH
emp AS (

SELECT
7369 AS empno,
'SMITH' AS ename,
20 AS deptno,

UNION ALL

SELECT
7499 AS empno,
'ALLEN' AS ename,
10 AS deptno,

UNION ALL

SELECT
7521 AS empno,
'WARD' AS ename,
30 AS deptno,
),

dept AS (

SELECT
10 AS deptno,
'DEVELOPMENT' AS dname,
'MAYNARD' AS loc

UNION ALL

SELECT
20 AS deptno,
'SALES' AS dname,
'HOUSTON' AS loc

UNION ALL

SELECT
30 AS deptno,
'RESEARCH' AS dname,
'PALO ALTO' AS loc
)

SELECT

e.empno,
e.ename,
e.deptno,
d.dname,
d.loc

FROM emp e
JOIN dept d ON e.deptno = d.deptno
;

同じようにCREATE TABLE ASにおいても、WITH句の前にCREATE TABLE ASを指定する必要があります。

CREATE TABLE dataset.emp_dept AS -- WITH句の前にを記載する必要がある

WITH
emp AS (

SELECT
7369 AS empno,
'SMITH' AS ename,
20 AS deptno,

UNION ALL

SELECT
7499 AS empno,
'ALLEN' AS ename,
10 AS deptno,

UNION ALL

SELECT
7521 AS empno,
'WARD' AS ename,
30 AS deptno,
),

dept AS (

SELECT
10 AS deptno,
'DEVELOPMENT' AS dname,
'MAYNARD' AS loc

UNION ALL

SELECT
20 AS deptno,
'SALES' AS dname,
'HOUSTON' AS loc

UNION ALL

SELECT
30 AS deptno,
'RESEARCH' AS dname,
'PALO ALTO' AS loc
)

SELECT

e.empno,
e.ename,
e.deptno,
d.dname,
d.loc

FROM emp e
JOIN dept d ON e.deptno = d.deptno
;

考え方としては、

  • WITH句はあくまでもSELECT文の一部である。(WITH句も含めてSELECT文)
  • INSERT SELECTCREATE TABLE ASの後にはSELECT文を記載する必要があるので、そのSQLの一部であるWITH句も同じくINSERT SELECTCREATE TABLE ASの後に記載する必要がある。

とうことでしょうか。

以上です。

株式会社エニグモ すべての求人一覧

hrmos.co

OAuth2Proxyは便利だよって話

こんにちは、インフラグループ Kubernetesチームの福田です。

突然ですが、Webアプリケーションでユーザの認証にOIDCを使うことはよくあると思います。
弊社でも様々な箇所でOIDCが利用されてます。
自社で開発しているWebアプリケーションや最近のログイン機能を持つOSSの多くは、OIDC Providerさえ用意すればOIDCを利用することができます。
しかし、現実的にはログイン機能を持たないOSSのWebアプリケーションでOIDC認証を使いたいケースや自前で開発したWebアプリケーションにおいてもわざわざOIDCのクライアント機能を追加実装するのが面倒なケースがあります。
そんな時に使えるのがOAuth2Proxyです。

OAuth2Proxyはリバースプロキシとして動作しながら、OIDCの認証をしてくれます。
具体的にはクライアントからのアクセスに対してOIDCの認証を行い、認証されたクライアントからのアクセスのみをバックエンドに通過させるといったことが可能です。

サンプル構成の構築

サンプル構成を通してKubernetes上での構築方法を紹介していきます。

サンプル構成ではOAuth2Proxyのバックエンドにnginxを利用し、OIDCプロバイダにはoktaを使いたいと思います。

okta(OIDC Provider)の設定

oktaのApplicationを作成します。

  1. Sign-in methodはOIDCを選択し、Application typeとしてWebを選択します。
  2. Grant typeではAuthorization CodeRefresh Tokenを選択します。
  3. Login Redirect URIsはお使いの環境に合わせて設定してください。(ここではhttps://corp.example.com/oauth2/callbackとしておきます。)
  4. また、作成後に生成されたClient IDClient Secretをメモしておきます。
  5. 最後にユーザのアクセス許可設定をします。

シークレット情報の作成

シークレット情報をSecretとして保存します。

kind: Secret
apiVersion: v1
metadata:
  name: my-credential
type: Opaque
data:
  client_id: **********
  client_secret: **********
  cookie_secret: **********

client_idclient_secretは"okta(OIDC Provider)の設定"のところでメモした値を使います。
cookie_secretにはランダムな値を使います。

Podの作成

OAuth2Proxyとnginxを構築します。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: sample
  name: sample
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: redis
        image: redis
        volumeMounts:
        - name: cache
          mountPath: /data
      - name: nginx
        image: nginx
      - name: oauth2-proxy
        image: bitnami/oauth2-proxy
        ports:
        - name: oauth-proxy
          containerPort: 80
        args:
        - --http-address
        - 0.0.0.0:80
        env:
        - name: OAUTH2_PROXY_UPSTREAMS
          value: http://localhost/
        - name: OAUTH2_PROXY_PROVIDER_DISPLAY_NAME
          value: okta
        - name: OAUTH2_PROXY_PROVIDER
          value: oidc
        - name: OAUTH2_PROXY_OIDC_ISSUER_URL
          value: https://sample.okta.com/oauth2/default
        - name: OAUTH2_PROXY_CLIENT_ID
          valueFrom:
            secretKeyRef:
              name: my-credential
              key: client_id
        - name: OAUTH2_PROXY_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              name: my-credential
              key: client_secret
        - name: OAUTH2_PROXY_PASS_ACCESS_TOKEN
          value: 'true'
        - name: OAUTH2_PROXY_EMAIL_DOMAINS
          value: '*'
        - name: OAUTH2_PROXY_REDIRECT_URL
          value: https://corp.example.com/oauth2/callback
        - name: OAUTH2_PROXY_COOKIE_SECURE
          value: 'false'
        - name: OAUTH2_PROXY_COOKIE_SECRET
          valueFrom:
            secretKeyRef:
              name: my-credential
              key: cookie_secret
        - name: OAUTH2_PROXY_SKIP_PROVIDER_BUTTON
          value: 'true'
        - name: OAUTH2_PROXY_COOKIE_NAME
          value: SESSION
        - name: OAUTH2_PROXY_COOKIE_SAMESITE
          value: lax
        - name: OAUTH2_PROXY_SESSION_STORE_TYPE
          value: redis
        - name: OAUTH2_PROXY_REDIS_CONNECTION_URL
          value: redis://localhost
        startupProbe:
          initialDelaySeconds: 5
          periodSeconds: 5
          tcpSocket:
            port: 6379
      volumes:
      - name: cache
        emptyDir: {}

nginxのPodに対してサイドカーとしてOAuth2Proxyコンテナを差し込んでいます。
redisコンテナがありますが、これはOIDCプロバイダーへのアクセスを減らすためのセッション情報のキャッシュとして使ってます。

サンプル構成の完了

IngressやServiceなどのリソース作成の説明は省略しますが、これで構築は完了です。
対象のURL(この記事の場合はhttps://corp.example.com)にアクセスするとoktaのサインイン画面が表示されます。

そして、サインインして認証をPASSするとnginxにアクセスできます。

参考リンク

まとめ

今回はOAuth2Proxyについて紹介させていただきました。
本記事を通して構築がとても簡単であることが分かったと思います。

OAuth2Proxyのようなツールを自前で社内開発しているところも多いのではないでしょうか。
メンテナンスコストの理由からそういった社内開発のアプリをOSSへ移行することを検討している場合はOAuth2Proxyは選択肢の1つとしてありかと思います。


株式会社エニグモ すべての求人一覧

hrmos.co

Global Buyma Glimpse Into the Future: Two-Day AI Conference Journey in Istanbul

Hello, this is Fernand from the Global Buyma Team. As an engineer, I am responsible for maintaining the English version of Buyma. I recently had the opportunity to attend an AI conference along with my manager. I’m excited to share our experiences and insights with you. So fasten your seatbelt, relax, and enjoy the journey through the world of AI that we embarked upon.

Merhaba!

On May 10-11, 2024, I had the privilege of immersing myself in the vibrant intersection of technology and tradition at the two-day AI conference organized by Mad Street Den in Istanbul. This city, which uniquely straddles two continents—Europe and Asia—offered the perfect backdrop for an event that brought together global leaders to explore the forefront of artificial intelligence across various sectors.

AI on Global Buyma

Global Buyma employs the capabilities of Vue.ai's AI service to curate the most suitable product images for display in search results. The AI evaluates and identifies the best quality image from those uploaded by sellers to represent each product.

Bridging Cultures, Advancing Technology

The conference kicked off with an insightful tour around Istanbul's historic centre, embodying the perfect blend of cultural heritage and modernity. Then we headed to the Sarnıç, a 1500-year-old cistern lying at the heart of Istanbul, which set the stage for an evening of engaging dialogue. Over dinner, we forged meaningful connections with fellow attendees, delving into spirited discussions about the transformative potential of AI and sharing diverse perspectives on its future impact.

・Dinner at The Sarnıç. Honoring the special guests of the event.

Key Highlights from the Conference

The following day, we journeyed to the magnificent Sait Halim Pasha Mansion, where leaders from diverse sectors, including pharmaceuticals, e-commerce, and logistics, shared their insights on implementing AI within their industries.

Ashwini Asokan and Anand Chandrasekaran, the founders of Mad Street Den, provided a comprehensive overview of how their tools are automating the way businesses operate, shifting the focus from infrastructure to innovation.

Then, it was followed by a thought-provoking panel discussion that shed light on the banking industry's cautious stance on migrating to cloud services, highlighting the need for policy changes and compliance measures to ensure security.

And much wide array of topics, extending from Zenyum's innovative application of AI in dental health assessments to the exciting reveal of Vue.ai's advanced personalization engine, designed to elevate the shopping experience. Their presentations vividly demonstrated the revolutionary capabilities and the expansive future of AI technologies.

・Panelists delved into AI's transformative impact and its common use cases

・Timo Weiss, Nithya Subramanian, and Sandal Kakkar engaged in a compelling discussion about "Gen AI: Existential Crisis or Competitive Advantage?"

Evening Soirée: A Sunset to Remember

After absorbing a plethora of information, it was time to let loose. The soirée, set against a breathtaking Istanbul sunset, provided a relaxed atmosphere for us to unwind, dance, and revel in the sumptuous dinner prepared for us.

・Turkish performing their traditional dance, Sufi whirling

Looking Ahead for Global Buyma

Discussions about these AI applications sparked ideas for enhancing the Global Buyma system, such as implementing auto-tagging based on product page content. Additionally, the personalization engine where AI analyzes shoppers' interactions would be perfect, allowing for dynamically tailored product displays and recommendations to cater to individual preferences. However, some guests noted that the use of AI for language translation in page displays requires further refinement.

 

Bye for now!

・From right: Ashwini Asokan, CEO & Founder of Mad Street Den, Hibaru Maywood, Head of Global Buyma

株式会社エニグモ すべての求人一覧

Argo Workflowsを使ったPersistentVolumeの定期バックアップ

Argo Workflowsを使ったPersistentVolumeの定期バックアップ

こんにちは。
インフラグループKubernetesチームの福田です。
今回はPV(PersistentVolume)の定期バックアップシステムについて紹介したいと思います。

PVのバックアップについて

PVのバックアップといっても色々とありますが、本記事ではスナップショットの取得を意味します。
スナップショットの取得はCSIが対応していれば、external-snapshotterを利用することで、CustomResourceを書くだけで実現できます。

extenal-snapshotterを全く知らない方は以下のAWSの記事が概要を掴む参考になるかと思います。

aws.amazon.com

バックアップシステムの仕組み

概要

システムの概要は以下のようになっています。

  • Argo Workflowsが定期的にVolumeSnapshotリソースを作成し、それをGitLabへプッシュする。
  • GitLabのCIがマニフェストをバリデーションする。
  • Argo CDがマニフェストのあるコードリポジトリの変更を検出して、それをKubernetesにデプロイする。

詳細

定期的に実行する処理

定期的な処理の実行はCronWorkflowで行っています。 単にCronJobとせず、CronWorkflowとした理由は、一度だけの実行や、定期処理の一時停止などがGUIで簡単にできるからです。

VolumeSnapshotリソースの生成

VolumeSnapshotリソースの生成を行うアプリケーションはGolangで実装した自前のコンテナアプリになります。
コンテナアプリは前述したCronWorkflowで実行されます。

世代管理機能

コンテナアプリはVolumeSnapshotマニフェストを生成すると共に、古いVolumeSnapshotマニフェストを削除するローテーション機能を持っています。
何世代分までのVolumeSnapshotマニフェストを維持するかは環境変数で指定可能になっています。
VolumeSnapshotマニフェスト間の新旧の比較はVolumeSnapshotマニフェスト生成時のタイムスタンプを独自のアノテーションに記載し、それを比較することで実現しています。

管理対象フラグ

ローテーション管理の対象とする否かのフラグを表現する独自のアノテーションもあります。
原則、コンテナアプリで生成されたVolumeSnapshotはこのフラグが立っています。
手動で作成したVolumeSnapshotやコンテナアプリによって作成された永続的に残しておきたいスナップショットについては、このフラグを下ろすことでローテーションの管理対象から外れて自動で削除されないようにできます。

生成されるマニフェストのサンプル

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: SAMPLE_NAME
  namespace: SAMPLE_NAMESPACE
  annotations:
    snapshot-tools.enigmo.co.jp/rotation: "true"
    snapshot-tools.enigmo.co.jp/rtime: 12345678
spec:
  source:
    persistentVolumeClaimName: SAMPLE_PVC
  volumeSnapshotClassName: SAMPLE_VSC
コードプッシュ

コンテナアプリはVolumeSnapshotマニフェストを作成、削除するとその変更をプッシュします。 プッシュ時のオプションでMergeRequest(githubでいうPullRequest)を作成し、CIが成功したら自動でMRをマージするようにしています。

CIの実行

MRに対しては手動によるマニフェストのデプロイと同じ条件でCIが周り、問題がなければそれをマージするようになっています。
これにより、システムが生成したマニフェストコードを特別扱いすることなく、統一したポリシー(例えば、フォーマッタやセキュリティチェック等のマニフェストに対するバリデーション)を適用できます。

Argo CDによるデプロイ

masterにマージされた変更を検出し、それをクラスタへ自動で適用するようにauto-syncを有効化しています。
また、世代管理機能によってVolumeSnapshotマニフェストの削除される場合もあるので、auto-pruneも有効化しています。
以下がArgoCD Applicationのサンプルになります。

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: snapshots
spec:
  generators:
  - list:
      elements:
      - namespace: SAMPLE_NS1
      - namespace: SAMPLE_NS2
      - namespace: SAMPLE_NS3
  template:
    metadata:
      name: '{{namespace}}-snapshot'
    spec:
      project: SAMPLE-PROJECT
      source:
        repoURL: GITLAB_URL
        targetRevision: master
        path: SAMPLE_PATH
      destination:
        server: K8S_ENDPOINT
        namespace: '{{namespace}}'
      syncPolicy:
        automated:
          prune: true

純粋なApplicationでなく、ApplicationSetとしている理由は我々は複数ネームスペースの運用をしているためです。 (Argo CDのApplicationは1つのネームスペースしかデプロイ先として指定できない。)

まとめ

Argo Workflowsを使ったPersistentVolumeの定期バックアップシステムについて紹介させていただきました。
実装方法としてオペレータパターンで開発する選択肢もありましが、cronの一時停止やカウントダウンタイマーなどをGUIで管理できる点からArgo WorkflowsのCronWorkflowを利用する実装を選択しました。
今回の記事がKubernetesネイティブな自動化システムの開発の参考になれば幸いです。

エニグモではエンジニアを含む各種ポジションで求人を募集しております。

株式会社エニグモ すべての求人一覧

hrmos.co

BUYMAのプロダクトマネージャー/ディレクターの役割とは?

「安心して何度も利用したくなるマーケットプレイス」を作る!UXデザイングループを紹介

エニグモでTech職種の採用や、採用広報を担当している廣島です。

この記事は、エニグモで新入社員向けのオンボーディング研修として実施する部署紹介プログラムの中で プロダクトマネージャーやディレクター、UI/UXデザイナーが所属するグループであるUXデザイングループマネージャーの山田さんがグループの説明をした内容をまとめた記事です。

グループのミッションや、チーム体制、カルチャー、どのように他チームと連携しながらプロジェクトを推進しているかについて説明します。最後に、BUYMAサービスやUXデザイングループの今後の展望や、UXデザイングループで仕事を行う魅力についてもお話しします。

※この記事は Enigmo Advent Calendar 2023の25日目の記事です※

BUYMAサービスについて

まずは、エニグモが運営するサービスのBUYMAについて説明します。
BUYMAは累計会員数1000万人超えの海外ファッションNo.1の通販(EC)サイトです。
世界中に在住する約20万人のパーソナルショッパー(出品者)から、ファッションを中心とした世界中のアイテムを購入できる「売り手」と「買い手」が個人であるCtoCのグローバルマーケットプレイスです。

主に個人の海外在住の日本人のネットワークを構築して海外から商品を購入することが可能で、多種多様な購入者の要望に答えています。商品の約半分は海外から届きます。
BUYMAが間に入ることで安心安全に海外の買い物ができるプラットフォームとして運営しています。

出品アイテムの特徴としては高級品×希少品の商品のラインナップが充実しており、海外限定デザインや、国内未上陸ブランド、国内完売入手困難品など高付加価値のアイテムを世界中から購入することができます。
BUYMAはファッションを主力にしつつも、インテリア・アウトドア、旅行などカテゴリーを拡大しています。

BUYMAのビジネスモデルの詳細は下記をご覧ください。
https://enigmo.co.jp/business/

UXデザイングループのミッション・業務内容とは?

エニグモディレクションを担うグループはUXデザイングループ(以下UXDグループ)と呼びます。
(UXとは「ユーザーエクスペリエンス」のことで、ユーザーが商品やサービスを通じて得られる体験を指します)

UXDグループとは名前の通り、ユーザーのPain(痛み)に向き合いながら、サービスをより使いやすく・より良くしていくために解決すべきことを考え、実行するグループです。
上記により、ユーザー体験を向上させ、安心して何度も利用したくなるようなマーケットプレイスBUYMAを成長させることがミッションです。

さらに、UXDグループはBUYMAサービスのプロダクト側(エンジニア・デザイナー)とビジネス側(MD、マーケティング・広告、データ、CS、オペレーション等)のちょうど中間に位置して両者を支えサービスを前進させる役割を担います。

具体的な業務領域は?

実際にどういった業務領域を担当しているかについてお話しします。
BUYMAの新機能・既存機能の改修・新サービスの企画・ディレクションからUI/UXと幅広く担当します。一般的なWeb業界の言葉でいうと具体的には下記のような業務です。

  • プロダクトマネジメント
  • プロジェクトマネジメント
  • 制作ディレクション / 進行管理
  • 各施策・プロジェクトの効果検証
  • UX視点からの企画提案 / サービスデザイン
  • 定性 / 定量調査
  • UIデザイン
  • フロントエンドプログラム(主にインタラクションデザイン部分)の実装

上記からも分かるようにUXDグループはディレクションを行うグループではあるが、UIデザインやフロントエンドプログラムなどの制作も行っていることが特徴的です。

フロントエンドプログラムは、Reactでの実装などはエンジニア部署のフロントエンドエンジニアが行いますが、インタラクションデザインなど実際に画面上で動くCSSJavaScriptの実装はUXDグループがおこないます。
その為、企画から制作までをシームレスにグループ内で行えユーザーの反応や外部環境に合わせてスピーディーに柔軟に対応することが可能です。

色々言いましたがまとめると業務内容は下記となります。

  • BUYMAの様々な課題に向き合い最適なスコープでユーザーに価値を提供する
  • ユーザーの反応を定性、定量の両側面から分析して企画・施策に繋げる
  • スキルとスキル(企画と開発)の間に立ち仲介・翻訳を行い、場合によっては制作も行う

グループの体制について

Webサービスにおける様々なスキルを持ったメンバーが集まっています。特徴としては、ディレクター部門であるが、制作するメンバーもいることです。一般的な職種で言うと、プロダクトマネージャー、ディレクター、SEOディレクター、UI/UXデザイナー、フロントエンドエンジニアが所属します。
前項で説明した業務領域全てを1人のメンバーが網羅しているのではなく、それぞれのメンバーの得意分野を活かしながら多岐にわたる領域をカバーし業務を行っています。

さらにグループは下記2つのチームに分かれています。
プロダクトマネジメントチームマーケティング戦略系の施策を担当するチーム
UI/UXチーム:UX戦略系の施策を担当するチーム

グループの体制を示した図です。
明確にチームが別れているのではなく、UXDグループのマネージャーがUI/UXチームのマネージャーを兼任していることもあり、定例は一緒に行っています。週1回グループの定例の他、プロジェクトベースで進めています。

実際の・プロダクトマネジメントチームとUI/UIXチームの業務は下記のインタビュー記事をご覧いただくと、よりイメージできるかと思います。 ・BUYMAのWebディレクター(PdM)紹介/エニグモの魅力は?UXDグループとは?インタビューしました!
UI/UXデザイナーインタビュー/ユーザーによりよい体験を届けプロダクト価値の向上に取り組む!

開発フロー・プロジェクトの中でのUXDグループの役割

プロジェクトの開発のフローの中で、UXDグループのメンバーが他職種メンバーと協力しながらどういった役割を担うのかについてお話しします。

プロジェクトや施策に伴う開発はエンジニアやビジネスサイドなど他チームメンバーと連携してプロジェクト型チームで進行します。
開発全体の流れは、UXDグループメンバー(ディレクター)が企画をまとめプロジェクトがスタートします。ディレクターとエンジニアのリードメンバーやビジネスサイドのメンバーで企画をどのようにシステムに落とし込むのかを要件定義します。その後、エンジニアのリードメンバーがシステム設計を担当し、タスクを分解してエンジニアメンバーアサインします。

プロジェクトや施策はディレクターから発案されることもあれば、マーケティングやカスタマーなど他の部門からの提案もあります。
要件定義はプロジェクトの特性により異なりますが、通常は主にディレクターが他のステークホルダーとのヒアリングを通じて要求を洗い出し、システムをどう作るかをエンジニアと共に要件定義を進めるのが主流です。

プロジェクトの目標やKPIの策定もディレクターが中心に行います。各プロジェクトでは、新規機能を開発する際に、「なぜこの新機能を開発するのか」「新機能リリースにより、ユーザーにどのような体験や行動を期待するか」「新機能リリース時の成功の定義は何か」などを、各プロジェクトのステークホルダーと明確にしています。

最後に

サービスの課題や今後の展望、エニグモでUXDにジョインする魅力、どういった方がマッチするかについて、マネージャーの山田さんにインタビューしました。

サービスの課題や今後の展望

今期の重点テーマである「BUYMAサービスをより安心できる体験にする」ことは引き続き進めていきます。安心と一言でいっても様々な側面が存在します。
たとえば、高級ブランドを扱っているため、ユーザーが商品が本物であるか不安に感じることもあります。これに対処するため、来期も偽物の不安を払拭するための施策を推進していきます。

また、ビジネスモデル上、高級品および希少品を扱っていることが強みですが、日用品と比べて購入頻度が低い傾向があります。そのため、サイトに訪れるタイミングが少なくサイトにユーザーが定着しにくく、サービスとユーザーの距離が遠くなることが課題です。
この課題に焦点を当て、ユーザーがサイトに定期的に訪れる動機づけや、サービスとの継続的な関係を築くための取り組みにも注力していきたいと考えています。

UXデザイングループの魅力

プロジェクトごとに各職種のメンバーがアサインされ、小規模チームが結成されます。そのためメンバー、一人ひとりが大きな裁量を持ち、エンジニア、デザイナー、ビジネスメンバーと密に連携し、距離が近く風通しも良く別部門という感じはしません。良い人(互いを尊重し、前向きなメンバー)が多いため、仕事上の人間関係による変なストレスがあまりなく、プロダクト開発方法や体制を共に進化させるマインドが根付いています。

また、グローバル×CtoCサービスという、BUYMA独自の仕組みやUXを構築するフェーズに携わることができます。出品者側と購入者側の双方のデータやユーザ―行動に基づくデータドリブンな開発が可能です。プロジェクトの成果を数値(売上、CVRなど)やユーザーの声によって直接実感することができます。

どういった方がマッチするか

経験やスキルも大事ですが、熱意やマインド面、カルチャーへの共感、エニグモへのバリューへのマッチを大切にしています。※バリューについての詳細はこちら
業務領域が幅広いため、俯瞰して物事を柔軟にアプローチできる方や、自らイニシアチブを取り推進できる方が活躍できるかと思います。

決まった案件をこなすだけでなく若手から裁量を持って働け、新規機能や新規事業の企画を自ら発案しユーザーに届け、世の中を変える可能性があります。
課題を見つけて積極的にアイデアを提案し進めていく方がマッチすると思います!

BUYMAや関連サービスのサービス品質を常に進化させ、国内および世界各国のユーザーがますますサービスを利用して喜びや満足を得られるような機能を、楽しみながら共に考え抜いていただける方にジョインいただけると嬉しいです。

BigQueryマニュアル「関数のベストプラクティス(Best practices for functions)」を試してみた結果(その1)

こんにちは、エニグモ 嘉松です。

BUYMAのプロモーションやマーケティングを行っている事業部に所属、その中のデータ活用推進室という部署で会社のデータ活用の推進やマーケティング・オートメーションツール(MAツール)を活用した販促支援、CRMなどを担当しています。

この記事は Enigmo Advent Calendar 2023 の 25 日目の記事です。

はじめに

この記事ではGoogleから提供されているBigQueryのオンライマニュアル「関数のベストプラクティス(Best practices for functions)」を試してみた結果を紹介していきます。

「関数のベストプラクティス」では、以下の4つのベストプラクティスが紹介されています。

  1. 文字列の比較を最適化する
  2. 集計関数を最適化する
  3. 分位関数を最適化する
  4. UDF を最適化する

はじめは4つ全てを1つの記事で紹介するつもりでしたが、記事を制作していく中で1つでもそれなりの記事ボリュームがあることが分かったので、読みやすさを重視して1つの記事で1つのベストプラクティスを紹介していくことにしました。 ということで、この記事は「その1」として「文字列の比較を最適化する」を試した結果を紹介していきます。

文字列の比較を最適化する

ベストプラクティス

  • 可能であれば、REGEXP_CONTAINS ではなく LIKE を使用します。

BigQuery では、REGEXP_CONTAINS 関数または LIKE 演算子を使用して文字列を比較できます。 REGEXP_CONTAINS は多くの機能を提供しますが、実行に時間がかかります。 REGEXP_CONTAINS ではなく LIKE を使用すると、処理時間が短くなります。 特に、ワイルドカード一致など、REGEXP_CONTAINS が提供する正規表現をフルに活用する必要がない場合には処理時間が短くなります。

次の REGEXP_CONTAINS 関数の使用を検討してください。

SELECT
  dim1
FROM
  `dataset.table1`
WHERE
  REGEXP_CONTAINS(dim1, '.*test.*');

このクエリは次のように最適化できます。

SELECT
  dim1
FROM
  `dataset.table`
WHERE
  dim1 LIKE '%test%';

なるほど。やはり機能の多い関数、複雑なパターンに対応できる関数よりも、単純なことしか出来ない関数の方が処理は軽い(速い)と。言われてみれば当たり前といえば当たり前ではありますが。単純なことしてできない関数が利用できるケースであれば、そちらを使ったほうが良い、正規表現による検索が必要ない場合は LIKEを使いましょう、ということですね。そもそも REGEXP_CONTAINS より LIKE を使うことを最初に考えるとは思うけどww(REGEXP_CONTAINSの方が汎用性が高いので常にREGEXP_CONTAINSを使っています、みたいな人は注意が必要です!)

試してみた

検証方法

REGEXP_CONTAINSLIKEを使ったクエリを実行して比較していきます。

比較する候補となる値は 経過時間消費したスロット時間の2つ、クエリの「実行の詳細」から取得できます。

それぞれの意味は以下の通りです。

  • 経過時間
    • クエリが開始されてから完了するまでの時間
      • サーバの使用状況などによる待機時間も含まれます
  • 消費したスロット時間
    • 「スロットとは、SQL クエリの実行に必要な演算能力の単位です。」(「BigQueryのコンソールの(?)」より)
    • スロットについての詳細は以下のGoogleのマニュアル「スロットについて」を参照ください。
    • BigQueryスロットは、BigQueryでSQLクエリを実行するために使用される仮想CPUということで、ざっくり言うとクエリ(SQLの実行)に使用したCPU使用量です。

今回の検証では 消費したスロット時間 を比較ます。(経過時間だとGoogleのその時のサーバの負荷といった外部要因が加わるため)

クエリはそれぞれ5回ずつ実行してその平均値を比較します。 クエリを実行するとクエリの結果がキャッシュされるので、キャッシュを使用しないように設定を行います。

なお、対象のテーブルは約1億件のテーブルを対象にしました。

キャッシュクリアの方法

  • 検証中はキャッシュを使用してしまうと正しい計測ができないので、キャッシュを使用しないように設定を行います。

https://cloud.google.com/bigquery/docs/best-practices-performance-functions?hl=ja#optimize_string_comparison

検証結果

消費したスロット時間(時間:分:秒)

試行回数 REGEXP_CONTAINS LIKE
1 0:03:06 0:02:50
2 0:03:22 0:02:29
3 0:03:02 0:02:36
4 0:03:06 0:02:20
5 0:02:56 0:02:18
平均 0:03:06 0:02:31
  • REGEXP_CONTAINSを使用した場合の平均の「消費したスロット時間」は 3分6秒 だったのに対して、LIKEでは 2分31秒 と35秒短縮、減少率は 80.79% と約80%に短縮、約20%改善されました。
  • この20%の改善をどう取るか。かなり短縮できたと取るか、さほど変わらないと取るか。
  • 個人的には、思ったほど変わらないな、という印象でした。
  • といのも、SQLではテーブルの結合方法(JOIN)や、絞り込み条件(WHERE句)をチューニングすると実行時間が半分になったり、場合によっては1/10になったりすることもざら、珍しくないため。
  • ただ、単純に LIKE を使うだけで20%削減されるのであれば、それは価値ありますよね。
  • このクエリで検索の対象としているカラムの平均の文字数は33文字と少なかったため大きな差が出なかった、もう少し文字数が多いカラムを対象にしたらもう少し差が出るのでは、と考え文字数の多いカラムを使って検証を実施しました。

追加検証結果(時間:分:秒)

  • 平均文字数が758文字のカラムを使って比較

消費したスロット時間(時間:分:秒)

試行回数 REGEXP_CONTAINS LIKE
1 0:59:53 0:55:26
2 1:02:00 0:53:43
3 1:02:00 0:51:51
4 1:01:00 0:50:43
5 1:04:00 0:52:02
平均 1:01:47 0:52:45
  • まずカラムの平均文字数が増えたことで「消費したスロット時間」も増加しています。
  • 平均文字数が33文字では約3分だったのに対して、758文字は約60分と約20倍に。
    • 当然ですが検索する文字数が増えればその分として処理の時間も増えますね。
  • REGEXP_CONTAINSを使用した場合の平均の「消費したスロット時間」は 1時間1分47秒 だったのに対して、LIKEでは 52分45秒 と9分2秒短縮、減少率は 85.39% と約85%に短縮、15%改善されました。
  • 平均文字数が33文字のときは約80%に短縮されたのに対して、758文字では約85%と短縮の率は減少しました。
    • この辺りの差は文字数のバラツキや検索する文字によっても差が出るのかもしれません。
  • 文字数の多いカラムでは LIKE を使うことでよりパフォーマンスに差が出ると思いましたが、大きな違いはありませんでした。

まとめ

  • REGEXP_CONTAINSLIKEを使ったクエリを実行して比較してみた結果、LIKEを使った方がクエリのパフォーマンスは確かに改善された!
  • その改善率は今回の検証では約20%だった!!
  • 可能であれば、REGEXP_CONTAINS ではなく LIKE を使用しましょう!!!

本日の記事は以上になります。

エニグモ Advent Calendar 2023もこの記事で最後になります。
最後まで読んでいただきありがとうございました。


株式会社エニグモ すべての求人一覧

hrmos.co

元SEがコーポレートエンジニアに転職してみた

こんにちは! 今年7月に中途入社しました、コーポレートエンジニア(コーポレートIT[CO-IT]チーム) のフルセです! 今年も終盤(早いですねぇ、、)ということで、 Enigmo Advent Calendar 2023 の季節になりました!! クリスマスイブである24 日目を担当する私は入社エントリ・振り返りなど中心に自由に書きたいと思います!

なお、この記事が少しでもコーポレートエンジニアに興味がある方や入社を検討してくださっている方の参考になれば幸いです。

Embed from Getty Images

簡単な経歴紹介

私の経歴についてざっくり下記のようにまとめました。

① 新卒でシステムインテグレータ企業にSEとして入社

→ITの基礎知識・技術を獲得! and IT業界の厳しさを痛感、、(大袈裟)

② システムインテグレータ企業を退職

→主にシステム相手の業務だったので、より人と接する仕事がしたいと考え決意

③ 某アパレル商社の情シスへ転職

→培った知識とスキルを活かし新たな業種へチャレンジしたかった!

→情シスが意外と性に合っていることに気づくきっかけに!

④ カナダへ留学

→ずっと挑戦したかった海外留学に挑戦!

→語学はもちろん人との出会いや経験から人生にプラスになった!

エニグモにコーポレートエンジニアとして入社

→帰国後にご縁があり、経験を活かしコーポレートエンジニアとして入社!

そもそもコーポレートエンジニアって何?

コーポレートエンジニアとは?
コーポレートエンジニアとは、企業内のIT活用や運用を担当するエンジニアのことです。

企業のIT環境の変化は著しく、テレワークの普及などによってクラウドサービスの利用も活発になり、SaaS型のID管理や統合認証サービスを利用する企業が増えてきました。そのなかでコーポレートエンジニアは、社内ITの構築・運用をはじめとして、社内業務の課題解決のための企画立案や部門間の調整まで幅広い業務を担います。

もっと詳しく知りたい方は、チームメンバーの記事を読んでみてください! tech.enigmo.co.jp

実際に入社してみて感じたこと

コーポレートエンジニアとして働く以上、社員の方々とのコミュニケーションをかなり重要だと考えていました*1。 しかし、エニグモはリモートワーク中心の会社のため、Face to Face でのお話しする機会が少なくどのように交流の輪を広げていこうか少し不安(そもそも入社直後というのもあり。。)に感じていました。

そんなときに、2M(Monthly Meet-up)*2に参加させていただきました。 そこでは色々な部署や役職の方と分け隔てなくフランクにお話しすることができ、一瞬にして不安が和らぎました。 やはり、新しい環境でのスタートはどうしても孤独感や不安がつきものだと思いますが、こういった交流会があると気持ちよくスタートダッシュが切れますよね!そもそも、こういった交流会を定期的に行なっている企業というのは少ないと思うので、これぞエニグモの良いところだと思っております。

それからというもの、毎月可能なかぎり参加し交流の輪を広げております!(無料で美味しいお酒とご飯が得られることも理由の一つなのですが笑)

2Mについて気になる方は、レポート記事がありますので是非ご覧いただければと! www.wantedly.com

入社してからの仕事とその感想

入社してからのざっくりとした仕事内容とその感想を書かせていただきました!

内容

  • 社内ヘルプデスク対応

    • 内容:PCの故障や不具合、各種ITサービスのトラブル対応等
    • 対応頻度:1〜2件/日
  • アカウント管理

    • 内容:アカウントの付与・削除から数量管理・購入
    • 対応頻度:1〜2件/週
  • IT機器の管理・キッティング

    • 内容:PCやモバイルデバイスの発注・管理・キッティング
    • 対応頻度:10〜20件/月
  • 社内ナレッジの作成・整備

    • 内容:手順書やルールの新規作成・ブラッシュアップ
    • 対応頻度:2回/週
  • 中途入社者向けのオリエン

    • 内容:PCのセットアップ方法の説明、社内ITサービスルールの共有
    • 対応頻度:1〜2回/月
  • 社内不要OA・IT機器廃棄対応

    • 内容:廃棄物回収対応
    • 対応頻度:2回/年
  • カオスマップ作成

    • 内容:社内で利用中サービスを整理と今後導入が必要なサービスの洗い出し
    • 対応頻度(見直し):2回/年

感想

一覧にしてみると、今年は色々なことをやらせていただいたと改めて感じています。 裁量を任せていただいているため、日々にマルチタスクをこなしておりますが、 それもまた自分のタスク管理力や遂行力の向上につながっていると感じます。

個人的にやりがいがあった業務としては、「社内不要OA・IT機器廃棄対応」です。 業者選定から始まり、やりとり(契約締結や回収日の調整など)、社内ナレッジ作成、各方面との連携など、これぞコーポレートエンジニアと感じるようなタスクだったため、とてもやりがいがありました。 それと山積みだった廃棄端末類をスッキリさせることができたという達成感が大きかったですね笑

またタスクとして面白かったものとしては、「カオスマップ作成」です。 初めてカオスマップというものを作成したので、そもそもカオスマップとは?からスタートし、他企業のカオスマップの調査、社内ITサービスの整理、今後導入が必要なITサービスの洗い出しを行いました。その後は、カオスマップをパズルのように作成する大変な作業がスタートし...と、ここでは書ききれないので、詳しい作成プロセスなどは機会があればまた書かせていただきたいと思います。(今回は割愛させていただきます。) それからというもの、試行錯誤を繰り返し、レビューを重ねてやっとの思いで完成させることができました。 結果として、時間をかけて取り組んだからこそ、サービスに対する理解や知見を広くできましたし、社内の課題(足りていないサービス)も炙り出すことができました。とはいえ、まだまだ未熟なカオスマップだと思っているので、これからもっと成熟させていきたいと思います。(楽しみ!)

こんな方に向いているかも(個人見解)

コーポレートエンジニアとしてのキャリアをスタートしたばかりの私ですが、 そんな私だからこそ考えるコーポレートエンジニアにはこんな人が向いているのではないかというのをまとめてみました!

私が思うに下記の3つの要素が肝になってくると思います。

コーポレートエンジニアの必要要素

  • 新しい情報・技術に興味があり探求するのが好きな方(好奇心)

    • 日々進化するIT技術やサービスをいち早く自社へ展開・導入するため
    • 最新の情報に敏感であれば、サービスなどがアップデートされたとしても柔軟に対応することができるため
  • 人とコミュニケーションするのが得意・好きな方(コミュニケーション力)

    • 業務上(問い合わせ対応・情報共有など)何かとコミュニケーションが必要になるため
  • 問題を切り分けて解決することが得意・好きな方(柔軟性)

    • コーポレートエンジニアは企業の多くの課題を与えられるので、一つ一つ解決し柔軟に対応することが求められるため

ここで書かせていただいた3つの要素は、かなり重要なポイントになると考えます。 コーポレートエンジニアの業務は、IT関連の何でも屋のようになりがちだと思っております。 そのためタスクを挙げ出したらキリがないうえ、日々変化します。 そのため、柔軟性はもちろん、社内外連携のためのコミュニケーション力やITサービスに関する知見を広げるための好奇心が重要になってきます。 もちろん、足りてないと感じている要素があったとしても、業務を通じてレベルアップすることは可能だと思います!(私も絶賛レベルアップ中...)

※あくまで個人の見解なのでご了承ください。

最後に

私もまだまだ未熟なので、日々進化するIT技術・情報に置いていかれないよう自己研鑽を続けつつ、 社内の課題を一つずつ着実に解決し、より良い社内環境づくりに励みたいと思います!

最後まで読んでいただき、ありがとうございました!!


株式会社エニグモ すべての求人一覧

hrmos.co

*1:情シス時代に業務上のコミュニケーションがかなり重要だと理解していたため

*2:毎月月初に開催される社内交流会