We’ve migrated our documentation to a new site, which means some URLs have changed.
Audience

セグメントマッチング詳解

はじめに

セグメントとは簡単にいうと特定のユーザーのサブセット、いわゆる「ターゲットオーディエンス」と定義できます。次の項目について、以降で説明します:

  • どのようにセグメントマッチングおよびセグメントアノテーションが行われるか。すなわち、ユーザーがセグメントに属すことをどのように定義し追跡するか。

  • どのようにユーザー属性、コンテント属性あるいはページ閲覧履歴を組み合わせてセグメントを作成するか。すなわち、複雑なセグメント定義をどのように表現するか。

  • ターゲットオーディエンスのサイズ推定についての考え方。特にオーディエンスがどのくらいのイベントを生み出すか。 

Segment types

Piano DMPは2種類のセグメントをサポートしています:

  • 外部セグメント: 他のシステムで定義されたセグメントからセグメントメンバーシップを取り込むタイプのセグメントです。/segment/data/update API でメンバーシップとインポートします。

  • トラフィックセグメント: Piano DMPでユーザーをトラッキングし、ユーザーがどのセグメントに属するかを判別しています。Piano DMPではトラフィックセグメントを定義するためにトラフィックフィルターを使用します。

本ページの以降の記述はトラフィックセグメントのみに関するものであり、特に記載がない限りは「セグメント」は「トラフィックセグメント」を指します。

セグメントのメンバーシップ

セグメントを定義するために使用される 「言語」は Traffic フィルターです。Traffic フィルターは、ユーザーではなくイベントに対して適用されます。イベントは「ページビューイベント」(例えば誰かがブラウザで URL を開いた)かもしれませんし、「DMP パフォーマンスイベント」(例えば誰かが表示された広告をクリックした)かもしれません。イベントからユーザーを割り出すのは容易です。なぜなら、私たちはどのユーザーがどのイベントを起こしたか追跡しているからです:

Traffic フィルターにマッチするイベントを一度でも起こしていたら、ユーザーはそのセグメントのメンバーである

彼/彼女が Traffic フィルターにマッチするイベントを一度も起こしていなければ、ユーザーはそのセグメントのメンバーではないとも言えます。この定義は重要なので覚えておいてください。なぜなら、一部のイベントだけが Traffic フィルターにマッチするというシナリオはよくあるためです。これについては後により詳細に見ていきます。

Traffic フィルターは /segment/create または /segment/update API、あるいは DMP UI のインタラクティブなセグメントエディターによって、セグメントに関連付けられます。

対象期間およびクロスサイトに関する注意

セグメントの Traffic フィルターはサイトグループに関連付けられ、対象期間をもちます。これによって、フィルターは対象のサイトグループのサイトで、指定された期間にに生じた特定のイベント(結果的にユーザー)を捕捉します。例えば、「直近二日間に私のサイトを訪れたユーザーが起こしたイベント」

期間およびサイトグループとの関連について、いくつかの制限があることに注意してください:

  • 現時点では、特別な設定を行わない限り過去 31 日間までの期間を指定することができます。このようなセグメントは対象のサイトグループのすべてのサイトに対して有効です。

  • 過去 31 日を超える期間については、現時点では弊社サポートにより明示的に「LTS 有効」かつ「DMP 有効」に設定されたサイトでのみサポートされます。さらに、このようなセグメントは、特定のユーザーをベースにして定義された場合には、複数のサイトを跨いで動作しません。(特に explodeUsers フィルターまたは having 構文が利用された場合。これらについてはこの後で説明します)

これらの制限は変更される可能性があります。

同じ制限が /dmp/push API によって送信されたパフォーマンスデータを基に定義されたセグメントに対しても適用されることに注意してください。言い換えると、セグメントの Traffic フィルターが dmp-event あるいは dmp-custom フィルターを使用している場合です。パフォーマンスデータと通常の Traffic データを結合するフィルターをもつセグメントについては、これらの制限は別のページでも触れられています。

セグメントのタグ付けと満了

億単位のアクティブユーザーや膨大な数のセグメントに対して、効率的にかつ継続的にどのユーザーがどのセグメントに属するのか追跡するのは、非常に負荷の高いタスクです。いかなる時でも、私たちが最優先にシステムに望むのは、次の質問に即座に答えてくれることです:

目の前のこのユーザーは、現在のどのセグメントのメンバーなのか?

ついでに言うと、この質問に答えてくれる API は /profile/user/segment です。このような API リクエストに迅速に回答するため、プラットフォーム側では、「セグメントタグ付け」プロセスを継続的に動かすことで、定期的にこの質問への回答を事前計算しています:

  • ユーザーがセグメントの対象になったことを追跡するタイミングは、どれくらいの頻度でセグメントタグ付けが行われるかに依存しています。現時点では、キャパシティーと時間帯により、おおよそ2時間〜4時間です。また、現在のキャパシティーの制約により、含まれるユーザーが 200 万人以下のセグメントだけがセグメントタグ付けによって処理されることに注意してください。

  • ユーザーがセグメントの対象ではなくなったことを追跡するタイミングは、セグメントの満了に依存します。現時点では、これはセグメントの対象期間と一致しますが、二日を超えることはありません。

現在のアプローチとキャパシティー制約は変更される可能性があります。

ユーザーのエンゲージメントを定義するセグメント(例えば「50 イベント以下のユーザー」)にとって、
セグメントタグ付けが現在とっているセグメントから外す処理の方法は課題となる可能性があります。
回避方法はセグメントの終点(例えば「51 イベント以上のユーザー」)が始点となるような別のセグメントを定義し、アプリケーションでこれらを AND および NOT オペレータで結合して利用することです(例えば「50 イベント以下で、51 イベント以上ではないユーザー」)。言い換えれば、一つ目のセグメントに属し、二つ目のセグメントに属さないユーザーを対象とします。

セグメントタグ付けプロセスにより、セグメントの Traffic フィルターが捕捉するイベントのユーザー数と、タグ付けプロセスがセグメントに属すとマーク済みのユーザー数には、通常わずかな差異があることに注意してください(segment フィルターには明確に二つのケースを区別する必要がある場合のためのオプションがあります)。

イベントベース マッチング

次の例をご覧ください:

$ # Users that generated events while visiting Oslo during the last two days. 
$ python cx.py /segment/create '{"siteGroupId":"12345", "name":"Users in Oslo", "description":"Users that we have seen surf the web when in Oslo.", "filters":[{"type":"time", "start":"-2d", "filter":{"type":"event", "group":"city", "item":"oslo"}}]}'
{
  "id": "8kwfp77cuw474p"
}

簡単のため、下では Traffic フィルター部分だけに絞っています:

$ # Events generated from Oslo during the last two days. 
{"type":"time", "start":"-2d", "filter":{"type":"event", "group":"city", "item":"oslo"}}

この例では、直近二日間にオスロで生じたイベントをもつユーザーにマッチするセグメントを作成しました。時間が経てば、直近二日間にオスロからイベントを起こし、あるユーザーはこのセグメントのメンバーになるかもしれませんし、直近二日間にオスロで生じたイベントがなく、あるユーザーはメンバーではなくなるかもしれません。

イベントの拡大

ここまでは問題ないと思います。しかし、該当のユーザーは物理世界を動き回るかもしれません。例えば、同じユーザーが、対象の期間内にオスロとストックホルムで見つかっていたかもしれません。このようなユーザーをオスロだけで見つかったユーザーと区別する必要があるケースもあります。このような場合使えるツールが explodeUsers フィルターおよび having 構文です。これらについて簡単に見ていきます。

explodeUsers フィルターは指定されたフィルター条件を満たすイベントを、そのユーザーが起こしたすべてのイベントに "explode" または "expand" します。例えば、オスロで見つかったユーザーはストックホルム滞在中にも、あるいは他の場所でもイベントを起こしたかもしれません。これらすべてのイベントを捕捉するためには、次のようなフィルター表現を使用できます:

$ # All events generated by users observed in Oslo during the last two days,
$ # also including those events generated from non-Oslo locations.
{"type":"explodeUsers", "filter":{"type":"time", "start":"-2d", "filter":{"type":"event", "group":"city", "item":"oslo"}}}

上のフィルターは次のフィルター表現と同義です:

$ # All events generated by users observed in Oslo during the last two days,
$ # also including those events generated from non-Oslo locations.
{"type":"user", "having":{"min":1, {"type":"time", "start":"-2d", "filter":{"type":"event", "group":"city", "item":"oslo"}}}

大まかに言うと、explodeUsers フィルターは having 構文の特殊な例と考えることができます。having 構文はイベントの回数に関してより細かい制限を表すために利用することができます。例えば:

$ # All events generated by users that have generated at least 10 Oslo events.
$ # I.e., all events (including non-Oslo events) generated by users that have
$ # been "active enough" in Oslo within the last two days.
{"type":"time", "start":"-2d", "filter":{"type":"user", "having":{"min":10, "filter":{"type":"event", "group":"city", "item":"oslo"}}}}

否定と補集合セグメント

さて、not オペレーターについてはどうでしょうか。否定(not)はイベントベースのマッチングをするにあたりややトリッキーになり得るため、より詳しく見ておく価値があります。次の例をご覧ください。オスロ以外の都市で一つでもイベントを起こしたユーザーにマッチします。:

$ # Events generated from outside of Oslo during the last two days. 
{"type":"time", "start":"-2d", "filter":{"type":"not", "filter":{"type":"event", "group":"city", "item":"oslo"}}}

言い換えると、直近二日間にオスロとストックホルム両方からイベントを起こしたユーザーがいたら、そのユーザーは「オスロユーザー」と「非オスロユーザー」両方のセグメントのメンバーとなります!直感的ではなく聞こえるかもしれません。ここで explodeUsers フィルターが役に立ちます。

前の例では二つのセグメントは相互に排他的でも、補完的でもありませんでした。not オペレータ単独では無理であれば、どうすれば補集合セグメントを定義できるのでしょうか。not オペレーターと explodeUsers を組み合わせればいいのです。例えば、次のセグメントはオスロで生じたイベントを全く持たないユーザーにマッチします。つまり、「オスロユーザー」セグメントの補集合です:

$ # The complement segment of "Oslo users".
{"type":"time", "start":"-2d", "filter":{"type":"not", "filter":{"type":"explodeUsers", "filter":{"type":"event", "group":"city", "item":"oslo"}}}} 

細かく見てみましょう:

  • 最も内側のイベントフィルターはオスロで生じたイベントにマッチします。

  • explodeUsers フィルターがこのイベントを同じユーザーが起こしたすべてのイベントに拡大します。

  • 最後に、not オペレーターが結果を反転します。すなわち、オスロで一つもイベントを起こしていないユーザーのイベントだけが残ります。

クロスイベント マッチング

explodeUsers フィルターはイベントを跨いだ高度なマッチングにも利用できます。例えば、オスロとストックホルム両方に行ったことがあるユーザーを識別するセグメントを作りたいとします(順番は問いません。もし順番が重要であれば explodeUsers にはそのためのモードがありますが、ここでは単純なケースで考えます)。フィルターマッチングは各々のイベントに対して行われ、一つのイベントは一つの場所に紐づくとすると、単純に制約を and オペレーターで結合しても何もマッチしません。イベントセットを拡大してくれるフィルターがあればいいのですが…ちょっと待ってください、あります!

$ # Users that have been to both Oslo and Stockholm during the last two days (alternative 1).
{"type":"time", "start":"-2d", "filter":{"type":"and", "filters":[
   {"type":"explodeUsers", "filter":{"type":"event", "group":"city", "item":"oslo"}},
   {"type":"event", "group":"city", "item":"stockholm"}
]}}
 
$ # Users that have been to both Oslo and Stockholm during the last two days (alternative 2).
{"type":"time", "start":"-2d", "filter":{"type":"and", "filters":[
   {"type":"event", "group":"city", "item":"oslo"},
   {"type":"explodeUsers", "filter":{"type":"event", "group":"city", "item":"stockholm"}}
]}}
 
$ # Users that have been to both Oslo and Stockholm during the last two days (alternative 3).
{"type":"time", "start":"-2d", "filter":{"type":"and", "filters":[
   {"type":"explodeUsers", "filter":{"type":"event", "group":"city", "item":"oslo"}},
   {"type":"explodeUsers", "filter":{"type":"event", "group":"city", "item":"stockholm"}}
]}} 

さて、これら三つのセグメント定義の選択肢は同等でしょうか?いえ、違います。これらはほぼ同一ですが、あらゆる面で同一ではありません。三つのフィルターは同じユーザーの集合を特定しますが、完全に同じイベントの集合を特定する訳ではありません!そのため、これら三つのフィルター選択肢と共に /traffic API を用いた場合、ユニークユーザー数は同一になりますがマッチするイベント数は異なります。なぜでしょうか?詳しく見ていきましょう:

  • 選択肢 1 では、オスロも訪れたユーザーが、ストックホルムで起こしたイベントにマッチさせます。

  • 選択肢 2 では、ストックホルムも訪れたユーザーが、オスロで起こしたイベントにマッチさせます。

  • 選択肢 3 では、オスロを訪れたユーザーのイベントとストックホルムを訪れたユーザーのイベントをクロスマッチさせます。この場合ストックホルムでもオスロでもないイベントにもマッチさせることができます。

プロファイルベース マッチング

セグメントはイベントに対する Traffic フィルターで定義できます。Traffic フィルターは大変理解しやすく、組み合わせて利用できるフィルターが数多く用意されています。ページビューイベントは、あるユーザーをあるコンテンツと関連付けるため、コンテンツを消費した、コンテンツに触れたということです。次のようなフィルター制約を表現したくなるのは当然です:

  • イベントを起こしたユーザーの属性、あるいは ユーザープロファイルに対するフィルター。例えば「男性が起こしたすべてのイベント」。これは、user-keyword または user-external フィルターで実現できます。

  • 消費されたコンテンツの属性、あるいはコンテンツプロファイルに対するフィルター。例えば、「Betty Page に言及しているページを読んでいるユーザーに関するすべてのイベント」これは、keyword フィルターで実現できます。

マッチングに関連してユーザープロファイルやコンテンツプロファイルの変更履歴や改定履歴は保持されないということは重要です。最新の情報だけが保持され、過去に起きたイベント(プロファイルは違っていたかもしれません)をフィルタリングする際にも最新の情報が利用されます。繰り返すと:

プロファイルベース フィルターが適用されるのは最新のプロファイルであり、イベント発生時点のプロファイルとは必ずしも一致しません。

言い換えれば、過去のイベントデータに適用されるフィルターは、参照されるプロファイルが変更されると、呼び出す度に異なる結果を返す可能性があります。

プロファイルのアベイラビリティ

プロファイルベースのフィルターが評価される前提は、プロファイルが存在し利用可能であることです。
これが当てはまらない状況として以下があります:

  • ページのクロールができていないため、またはコンテンツプロファイルがプッシュされていないため、
    コンテンツプロファイルが存在しない。例えば、新しく公開されたページでは、ごくわずかの間、
    コンテンツプロファイルが紐付いていない URL に対してイベントを受け取ることになります。

  • キャパシティーの理由により、コンテンツプロファイルデータのすべてが保持されないことがあります。現時点では、60 日より前にクロールしたページのコンテンツプロファイルはマッチングに利用できません。

  • キャパシティーの理由により、ユーザープロファイルデータのすべてが保持されないことがあります。
    現時点では、直近 7 日間利用がなかったユーザーのプロファイル(またはその一部セクション)はマッチングに利用できません。

現在のキャパシティー制約は変更される可能性があります。

コンテンツプロファイルとのマッチング

keyword フィルターを含むセグメント定義は、特定の制約を満たすページに関連するすべてのイベントにマッチします。例えば、このフィルターはすべてのスポーツ記事、URL からスポーツ関連とされた記事、の閲覧に関するイベントにマッチします:

$ # Users that have read at least one sports article during the last two days.
{"type":"time", "start":"-2d", "filter":{"type":"keyword", "group":"taxonomy", "item":"articles/sports"}}

言い換えると、上記のフィルターは最低一つのスポーツ記事を読んだユーザーを特定します。

では、同じ期間に一つもスポーツ記事を読まなかったユーザーの特定はどうでしょうか?上の議論を思い出すかもしれませんが、否定は時にトリッキーです。求める結果を得るためには、not および explodeUsers フィルターを組み合わせなくてはいけません:

$ # Users that haven't read any sports articles during the last two days.
{"type":"time", "start":"-2d", "filter":{"type":"not", "filter":{"type":"explodeUsers", "filter":{"type":"keyword", "group":"taxonomy", "item":"articles/sports"}}}}

単純に最も内側の元のフィルターに not フィルターを被せていたら、タクソノミーが設定されていないまたはタクソノミーがスポーツ以外に設定されているページの全イベントがマッチしたでしょう。しかし、スポーツ記事の読者もまたそのようなスポーツ以外の記事を読んだかもしれません。スポーツ記事の読者を除きたいので、追加の explodeUsers フィルターが必要なのです。

既にクロスイベント マッチングについて行った議論と同様に、相互排他的なキーワードに対するクロスプロファイル マッチングをする際には、explodeUsers フィルターが必要です。例えば、スポーツに関する記事とテクノロジーに関する記事両方を読んだユーザーにマッチするには:

$ # Users that, within the last two days, have read at least one sports
$ # article and at least one technology article. 
{"type":"time", "start":"-2d", "filter":{"type":"and", "filters":[
	{"type":"explodeUsers", "filter":{"type":"keyword", "group":"taxonomy", "item":"articles/sports"}},
	{"type":"explodeUsers", "filter":{"type":"keyword", "group":"taxonomy", "item":"articles/technology"}}
]}}

カテゴリーは相互排他的なので、explodeUsers が必要です。両方のキーワードに同時にマッチするページはありません。そうでなければ、例えばカテゴリー:スポーツとページクラス:記事を組み合わせるためには、explode のない単純なフィルターで十分です。

ここでも、例えばスポーツ記事が読まれた回数に制約を加えたければ、user フィルターの having 構文を explodeUsers フィルターの代わりに用いることができます:

$ # Users that have read sports pages at least 10 times within the last
$ # two days. Note that some of the events could be for the same page.
{"type":"time", "start":"-2d", "filter":{"type":"user", "having":{"min":10, "filter":{"type":"keyword", "group":"taxonomy", "item":"articles/sports"}}}}

ユーザープロファイルとのマッチング

user-keyword フィルターまたは user-external フィルターを含むセグメント定義は、特定の属性をもったユーザーの起こしたすべてのイベントにマッチします。例えば、スポーツに長期的な関心を示し、直近二日間にサイトを訪れたユーザーを特定するには、次のフィルターを定義することができます:

$ # Users that have visited the site within the last two days, and that
$ # have shown a longterm interest in sports. The longterm interest is
$ # computed over a longer time span. It is possible to impose constraints
$ # on the "degree of interestedness", too. (Not shown here).
{"type":"time", "start":"-2d", "filter":{"type":"user-keyword", "group":"cxd-categories", "item":"sports"}}

ユーザープロファイルに適用されるフィルターは自動的に該当するユーザーのすべてのイベントに展開されるため、否定やクロスプロファイル アッチングの際でも explodeUsers フィルターは不要です。該当するユーザーが起こしたイベントの回数に制約をつけたい場合のみ、having 構文が必要となります:

$ # Users that have not shown a longterm interest in sports.
$ # Note that since we don't impose a constraint on the
$ # "degree of interestedness", this will also exclude users
$ # that have shown a very weak longterm interest in sports.
{"type":"time", "start":"-2d", "filter":{"type":"not", "filter":{"type":"user-keyword", "group":"cxd-categories", "item":"sports"}}}


$ # Users that have shown a longterm interest in both sports and technology.
$ # Note that since we don't impose a constraint on the "degree of interestedness",
$ # this will also include users that have shown a very weak longterm interest in
$ # those topics.
{"type":"time", "start":"-2d", "filter":{"type":"and", "filters":[
	{"type":"user-keyword", "group":"cxd-categories", "item":"sports"},
	{"type":"user-keyword", "group":"cxd-categories", "item":"technology"}
]}}


Last updated: