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では抽出失敗にはならなかったということが分かりました。

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

project_idはどこへ消えた?
どうやら全部public.project_contentsという別のTableに格納されるようになったらしいです。どうして。
以下がそのTableの紹介。

試しに,content_typeの種類を調べてみます。弊チームが使っているサイトでは以下の種類がありました。自チームではprojectの階層構造やデータソースとワークブックの格納先を取得しているので,それらの情報をここから得ることができれば修正が可能そうです。
とくに,content_type = 'project'であるとしたときにも,projects_contentsの中にproject_idが格納されています。これがそのプロジェクトの親プロジェクトとなるので,これをpublic.projectsのparent_project_id代わりに使えれば,プロジェクトの階層構造も取得できそうです。
projectworkbookdatasourceflow_draftflowlensmetric
修正する
データソースやワークブックの場合は,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から得られていることが分かります。

一方,プロジェクトは階層構造を得たいので,再帰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がちゃんと取得できていることが分かります。
こちらが修正前。

そして修正後です。

まとめ
public.datasourcesやpublic.workbooksのproject_id,また,public.projectsのparent_project_idは最新のバージョンでは使えなくなったので,代わりにpublic.projects_contentsのproject_idを使いましょう。
おわりに
抽出時にエラーが出なかったので,変わらず取得できるんだと思いこんでしまいました。こういうサイレント修正(?)はどうやって事前に気づけばよいのでしょうか?どこかで告知されていたら自分のアンテナが小さかっただけでよいのですが
余談
現在,弊社Rakutenではモバイルの社員紹介キャンペーンを実施しております。
下記リンクから,Rakuten会員でログインいただくと,回線変更で最大14,000ポイントがもらえるので,ご興味ある方はぜひアクセスしてみてください!
Discussion