🍊

Tableau Server Repositoryアップグレード後public.projects_contentsを使わないといけなかった話

に公開

はじめに

こんにちは。Rakutenでデータエンジニアをやっています。今自分のいるチームではTableau Serverを使用しています。さらに,Tableauの利活用を促進すべく,誰がTableau Server上でどんなアクションを行なっているかを確認しています。具体的には,誰がどのViewにアクセスしたか・どのViewをPublishしたか・どのデータソースにアクセスしたか,といった情報です。

これを得るためにはTableau Server Repositoryからデータを取得するのですが,先日v2024.2からv2025.1へバージョンアップした際に,データの持ち方が変わったようで。具体的には,そのコンテンツが格納されているプロジェクト情報が別のTableに入ることになりました。その修正内容をここに記します。

環境

  • Mac OS Sonoma 14.4.1
  • Tableau Server Repository: v2024.2 → v2025.1

どこで気づいたか

冒頭にも書いてあるとおり,自分のチームではTableau ServerにおけるユーザのアクションをTableau Server Repositoryから取得して分析できるようにしています。

ある日,データソースやワークブックが格納されているプロジェクトの情報が,Tableau Serverのアップグレード後から得られなくなってしまいました。ただしデータソースの更新におけるエラーは発生していませんでした。

カスタムSQLを使って直にpostgresqlへ叩いてみると,たしかにproject_idの列がNULLになっています。値が存在せず,列が消えたわけじゃないので,カスタムSQLでは抽出失敗にはならなかったということが分かりました。

project_id_null_datasources

同様に,public.projectsではparent_project_idの値がNULLになっていることが分かりました。

parent_project_id_null

project_idはどこへ消えた?

どうやら全部public.project_contentsという別のTableに格納されるようになったらしいです。どうして。

以下がそのTableの紹介。

https://tableau.github.io/tableau-data-dictionary/2025.1/data_dictionary.htm

projects_contents_introduction

試しに,content_typeの種類を調べてみます。弊チームが使っているサイトでは以下の種類がありました。自チームではprojectの階層構造やデータソースとワークブックの格納先を取得しているので,それらの情報をここから得ることができれば修正が可能そうです。

とくに,content_type = 'project'であるとしたときにも,projects_contentsの中にproject_idが格納されています。これがそのプロジェクトの親プロジェクトとなるので,これをpublic.projectsのparent_project_id代わりに使えれば,プロジェクトの階層構造も取得できそうです。

  • project
  • workbook
  • datasource
  • flow_draft
  • flow
  • lens
  • metric

修正する

データソースやワークブックの場合は,content_typeを'datasource’とか’workbook’などと指定してあげて,JOINさせれば良さそうでした。

SELECT 
    t.id,
    t.created_at,
    t.project_id,
    pc.id AS project_contents__id,
    pc.project_id AS project_contents__project_id
FROM 
    public.datasources AS t
    LEFT JOIN public.projects_contents AS pc
        ON t.id = pc.content_id 
        AND pc.content_type = 'datasource'
        AND t.site_id = pc.site_id 

こうして得られる出力結果が下記。public.datasourcesではNULLとなっているproject_idが,代わりにprojects_contentsから得られていることが分かります。

project_contents_project_id

一方,プロジェクトは階層構造を得たいので,再帰SQLを使って親→子→孫→…と辿っていきます。サンプルクエリは次のような感じです。UNION ALLする前半ではまず最上位のプロジェクトを取得し,後半でそれ以降の各階層のプロジェクトをそのひとつ上位のプロジェクトと紐づけながら,循環的に呼び出すことで末端階層まで取得します。各階層ではpublic.projectsとpublic.projects_contentsのJOINをしていますね。

WITH RECURSIVE rec_projects(
    project_level,
    parent_project_id,
    project_id,
    project_structure_name,
    project_hierarchy,
    top_project
) AS (
    SELECT
        CAST(1 AS NUMERIC) AS project_level,
        pc.project_id AS parent_project_id,
        p.id AS project_id,
        CAST(p."name" AS varchar) AS project_structure_name,
        LPAD(CAST(p.id AS varchar(5)), 5, '0') AS project_hierarchy,
        LPAD(CAST(p.id AS varchar(5)), 5, '0') AS top_project
    FROM
        public.projects AS p
        LEFT JOIN public.projects_contents AS pc ON p.id = pc.content_id
        AND p.site_id = pc.site_id
        AND pc.content_type = 'project'
    WHERE
        p.site_id = XXXXX -- ここは自チームが使用しているサイトIDに置き換えます
        AND pc.project_id IS NULL
    UNION
    ALL
    SELECT
        r.project_level + 1 AS project_level,
        pc.project_id AS parent_project_id,
        p.id AS project_id,
        r.project_structure_name || ' >> ' || CAST(p."name" AS varchar) AS project_structure_name,
        r.project_hierarchy || '>>' || LPAD(CAST(p.id AS varchar(5)), 5, '0') AS project_hierarchy,
        CAST(
            substring(
                r.project_hierarchy
                FROM
                    1 FOR 5
            ) AS varchar(5)
        ) AS top_project
    FROM
        public.projects AS p
        LEFT JOIN public.projects_contents AS pc ON p.id = pc.content_id
        AND p.site_id = pc.site_id
        AND pc.content_type = 'project'
        INNER JOIN rec_projects AS r ON r.project_id = pc.project_id
    WHERE
        p.site_id = XXXXX -- ここは自チームが使用しているサイトIDに置き換えます
        AND r.project_level <= 50
)

この修正後のクエリを使って得られた結果を,修正前と比べてみます。マスキングしているので見づらいですが,左から5列目のparent_project_idがちゃんと取得できていることが分かります。

こちらが修正前。

before_modification

そして修正後です。

after_modification

まとめ

public.datasourcespublic.workbooksproject_id,また,public.projectsparent_project_idは最新のバージョンでは使えなくなったので,代わりにpublic.projects_contentsproject_idを使いましょう。

おわりに

抽出時にエラーが出なかったので,変わらず取得できるんだと思いこんでしまいました。こういうサイレント修正(?)はどうやって事前に気づけばよいのでしょうか?どこかで告知されていたら自分のアンテナが小さかっただけでよいのですが

余談

現在,弊社Rakutenではモバイルの社員紹介キャンペーンを実施しております。
下記リンクから,Rakuten会員でログインいただくと,回線変更で最大14,000ポイントがもらえるので,ご興味ある方はぜひアクセスしてみてください!

https://r10.to/hNCoik

Discussion