# 细分语言

Pushwoosh 提供了一个强大的细分引擎，用于根据标签值构建精细的细分 (Segments)。**细分语言**是一种编写和组合细分标准的特定方式，用于描述符合这些标准的特定用户组，并将其视为单个受众细分。

本文描述了细分语言的基本概念和语法，并提供了为各种情况构建细分标准的综合示例。

## 基础知识

您的用户群中的每个设备都通过**标签 (Tag) 值**关联了特定的属性。

例如，假设一个名为 Jane 的用户住在东京，年龄为 28 岁。该用户的设备将设置以下标签：

*   姓名：Jane
*   城市：东京
*   年龄：28

要定位 Jane，您需要按如下方式描述一个细分：

`T("Name", eq, "Jane") * T("Age", eq, 28) * T("City", eq, "Tokyo")`

这种条件的组合是一个**筛选表达式**，在细分语言中用于描述用户组，即受众细分。

## 筛选表达式

筛选表达式是一个字符串，包含一个或多个描述您所需细分的条件。

### 条件

每个条件都描述了一个设备细分，这些设备符合该条件中指定的标准。

例如，以下条件构建了一个居住在东京的用户细分：

`T("City", e, "Tokyo")`

其中

*   T 是一个标签（条件类型）；
*   eq 是一个要应用的运算符；
*   "Tokyo" 是与用户设备关联的标签值。

#### 条件类型

以下条件类型可用于细分：

*   **A** (Application) – 描述安装了特定应用的设备细分。别名：**App**、**Application**；
*   **T** (Tag) – 描述具有指定标签值的设备细分；
*   **AT** (App-scoped tag) – 在特定应用程序内查找标签值；需要应用代码作为第一个参数。别名：**Tag**；
*   **Event** – 描述触发了特定 Pushwoosh 事件的设备细分；
*   **Geo** – 描述特定地理半径内的设备细分；
*   **BTTS** – 根据设备的最佳发送时间描述设备细分；
*   **Updated** – 根据设备的最后更新时间戳描述设备细分；
*   **Segment** – 通过其代码引用另一个筛选器/细分；

### 条件操作

为了构建复杂的细分，可以在筛选表达式中对条件应用以下操作：

#### 并集 (+)

连接各个细分，即构建一个新细分，其中的用户至少匹配指定条件中的一个。

<img src="/filters-segmentation-language-1.webp" alt=""/>

例如，要定位居住在东京或大阪的用户，您需要使用以下条件来描述该细分：

`T("City", eq, "Tokyo") + T("City", eq, "Osaka")`

<Aside type="note">
等同于逻辑**析取**（**OR**）。也可以写作 **or** 运算符。
</Aside>

#### 交集 (*)

构建一个同时属于由条件描述的两个细分的用户细分。因此，只有那些符合您指定的每个条件的用户才会被包含在内。

<img src="/filters-segmentation-language-2.webp" alt=""/>

以下表达式描述了一个既居住在东京又指定了姓名的用户细分：

`T("City", eq, "Tokyo") * T("Name", any)`

<Aside type="note">
类似于逻辑**合取**（**AND**）。也可以写作 **and** 运算符。
</Aside>

#### 差集 (\\)

构建一个属于其中一个描述的细分但不属于另一个细分的用户细分。

<img src="/filters-segmentation-language-3.webp" alt=""/>

居住在东京但未提供姓名的用户将如下描述：

`T("City", eq, "Tokyo") \ T("Name", any)`

<Aside type="note">
等同于逻辑**否定**（**NOT**）。也可以写作 **not** 运算符。
</Aside>

#### 括号

确定在筛选表达式中对条件执行操作的顺序。

例如，以下筛选表达式将首先获取 12345-67890 订阅者中年龄为 18 岁的细分，然后减去该细分中的所有男性：

`( A("12345-67890") * T("Age", eq, 18) ) \ T("Gender", eq, "Male")`

## 标签条件运算符

每种标签类型都应用其自己的运算符。

### 整数标签运算符

*   **eq** - 等于指定值
*   **noteq** - 不等于指定值
*   **lte** - 小于或等于指定值
*   **gte** - 大于或等于指定值
*   **in** - 任何指定值之一
*   **notin** - 不等于任何指定值
*   **between** - 在指定范围内
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备

<Aside type="note" title="整数标签语法示例">
`T("int", eq, 42)`
</Aside>

### 字符串标签运算符

*   **eq** - 等于指定值
*   **noteq** - 不等于指定值
*   **startswith** - 以指定前缀开头
*   **endswith** - 以指定后缀结尾
*   **contains** - 包含指定子字符串
*   **in** - 等于任何指定值之一
*   **notin** - 不等于任何指定值
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备

<Aside type="note" title="字符串标签语法示例">
* `T("str", eq, "kangaroo")` - 精确匹配
* `T("str", startswith, "kang")` - 以 "kang" 开头
* `T("str", endswith, "roo")` - 以 "roo" 结尾
* `T("str", contains, "nga")` - 字符串中任意位置包含 "nga"
</Aside>

### 列表标签运算符

*   **in** - 具有任何指定标签值的设备
*   **notin** - 设备没有关联任何指定的标签值
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备

<Aside type="note" title="列表标签语法示例">
`T("list", notin, ["kangaroo", "raccoon"])`
</Aside>

### 日期标签运算符

*   **eq** - 等于指定日期
*   **noteq** - 不等于指定日期
*   **lte** - 在指定日期之前或当天
*   **gte** - 在指定日期之后或当天
*   **in** - 等于任何指定日期之一
*   **notin** - 不等于任何指定日期
*   **between** - 在指定范围内
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备
*   **match** - 匹配指定的年份中的月份和月份中的日期。

<Aside type="note" title="match 运算符示例">


* `AT("XXXXX-XXXXX", "Date tag", match month 4 day 1)` - “Date tag” 设置为任意年份 4 月 1 日的设备。
* `AT("XXXXX-XXXXX", "Date tag", match month "now" day 13)` - “Date tag” 设置为当月 13 日的设备。
* `AT("XXXXX-XXXXX", "Date tag", match month "now" day "now+2")` - “Date tag” 设置为后天的设备。常见用例：生日祝福。
</Aside>

<Aside type="note" title="周年纪念和生日细分的 Match 运算符示例">
您可以[根据重复的日历日期（如生日或周年纪念日）对用户进行细分](/zh/product/audience-data-and-segmentation/segmentation/create-segments/anniversary-segments)。在这些情况下，只考虑月和日，而忽略年。

* `AT("XXXXX-XXXXX", "birthday", match month "now" day "now")`
   **定位今天生日的用户**（与今天的日和月相同）。
   *用此在用户生日当天发送生日祝福或特别优惠。*

* `AT("XXXXX-XXXXX", "birthday", match month "now" day "now+N")`
   **定位 N 天后生日的用户**（相同的月和日，从今天起 N 天后）。
   *用此提前为用户做准备，例如，发送倒计时消息或即将到来的活动提醒。*

* `AT("XXXXX-XXXXX", "birthday", match month "now" day "now-N")`
   **定位 N 天前生日的用户**。
   *用此发送迟到的生日消息或后续跟进，如反馈请求。*
* `AT("XXXXX-XXXXX", "birthday", match month "now" day N)`
   **定位生日在当月第 N 天的用户**，无论年份如何。
   *当计划与特定日期相关的固定月度活动时使用（例如，每月的 10 号发送忠诚度奖励）。*
</Aside>

*   **daysago eq** - 等于当前日期之前的指定天数
*   **daysago noteq** - 不等于当前日期之前的指定天数
*   **daysago lte** - 小于或等于当前日期之前的指定天数
*   **daysago gte** - 大于或等于当前日期之前的指定天数
*   **daysago between** - 在指定的天数之间

<Aside type="note" title="daysago 运算符示例">

* `T("Date tag", daysago, eq, 0)` - 当天从 00:00 到当前时刻
* `T("Date tag", daysago, eq, 1)` - 从前一天的 00:00 到当天的 00:00
* `T("Date tag", daysago, gte, 1)` - 直到当天 00:00 之前的所有时间
* `T("Date tag", daysago, lte, 7)` - 从 6 天前的 00:00 到当前时刻
* `T("Date tag", daysago, between, [2,7])` - 从 7 天前到 2 天前。
</Aside>

*   **minutesago lte** - 小于或等于当前时刻之前的指定分钟数
*   **minutesago gte** - 大于或等于当前时刻之前的指定分钟数

<Aside type="note" title="minutesago 运算符示例">

* `T("Date tag", minutesago, lte, 30)` - 最近 30 分钟；
* `T("Date tag", minutesago, gte, 60)` - 60 分钟或更久以前；
* `T("Date tag", minutesago, lte, 1)` - 在最后一分钟内。
</Aside>

*   **daysahead** - 从当前日期（UTC）起的 N 到 M 天内，两端均包含

<Aside type="note" title="daysahead 运算符示例">

`daysahead` 接受一个 `[from, to]` 区间（从今天 UTC 午夜算起的天数，两端均包含）。与 `daysago` 不同，它没有子运算符——只有区间形式。

* `T("Date tag", daysahead, [0, 0])` - 当天从 00:00 到 23:59:59
* `T("Date tag", daysahead, [1, 1])` - 第二天从 00:00 到 23:59:59
* `T("Date tag", daysahead, [2, 5])` - 从 2 天后的开始到 5 天后的结束之间的任何时刻
</Aside>

<Aside type="note" title="date 运算符示例">
* `T("Date tag", eq "2022-12-05 00:00:00")`
</Aside>

### 布尔标签运算符

*   **eq** - 等于指定值
*   **noteq** - 不等于指定值
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备

<Aside type="note" title="布尔标签语法示例">
 `T("bool", eq, true)`
</Aside>

### 价格标签运算符

*   **eq** - 等于指定值
*   **noteq** - 不等于指定值
*   **lte** - 小于或等于指定值
*   **gte** - 大于或等于指定值
*   **in** - 等于任何指定值之一
*   **notin** - 不等于任何指定值
*   **between** - 在指定范围内
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备

<Aside type="note" title="价格标签语法示例">
`T("price", between, ["4.2", "6.9"])`
</Aside>

### 版本标签运算符

*   **eq** - 等于指定值
*   **noteq** - 不等于指定值
*   **lte** - 小于或等于指定值
*   **gte** - 大于或等于指定值
*   **in** - 等于任何指定值之一
*   **notin** - 不等于任何指定值
*   **between** - 在指定范围内
*   **any** - 为该标签设置了任何值的设备
*   **notset** - 未为该标签设置值的设备

<Aside type="note" title="版本标签语法示例">
`T("version", lte, "4.2")`
</Aside>

## 事件条件运算符

<Aside type="note">
请记住，事件条件是特定于应用的，因此在您的筛选表达式中应指定应用代码和事件名称。
</Aside>

### 事件计数

*   **count gte** - 触发事件次数大于或等于 n 次的设备
*   **count lte** - 触发事件次数小于或等于 n 次的设备
*   **count eq** - 触发事件次数正好为 n 次的设备
*   **count noteq** - 触发事件次数不等于 n 次的设备

<Aside type="note" title="事件计数语法示例">
 `Event("11111-11111", "Level reached", count gte 10) // 11111-11111 是应用代码`
</Aside>

### 事件日期

*   **date gte** - 在指定日期之后或当天触发事件的设备
*   **date lte** - 在指定日期之前或当天触发事件的设备
*   **date eq** - 恰好在指定日期触发事件的设备
*   **date noteq** - 在任何时间触发事件但不在指定日期的设备
*   **date in** - 在任何指定日期触发事件的设备
*   **date notin** - 在任何时间触发事件但不在任何指定日期的设备
*   **date between** - 在指定时间段内触发事件的设备
*   **date daysago eq** - 事件触发日期等于当前日期之前的指定天数
*   **date daysago noteq** - 事件触发日期不等于当前日期之前的指定天数
*   **date daysago lte** - 事件触发日期小于或等于当前日期之前的指定天数
*   **date daysago gte** - 事件触发日期大于或等于当前日期之前的指定天数
*   **date daysago between** - 事件触发日期在指定的天数之间
*   **date daysahead** - 事件触发日期在从当前日期起的指定天数内（区间两端均包含，完整语义请参见上文的日期标签运算符）
*   **date minutesago lte** - 事件触发日期小于或等于当前时刻之前的指定分钟数
*   **date minutesago gte** - 事件触发日期大于或等于当前时刻之前的指定分钟数

<Aside type="note" title="事件日期语法示例">

- `Event("11111-11111", "Level reached", date gte "2022-01-01 01:02:03")`
- `Event("11111-11111", "Level reached", date in ["2022-01-01 01:02:03", "2022-01-01 02:03:04"])`
- `Event("11111-11111", "Level reached", date between "2022-01-01 01:02:03" "2022-01-01 02:03:04")`
- `Event("11111-11111", "Level reached", date daysahead 0 7)` - 触发日期在未来 7 天内的事件
- `Event("11111-11111", "Level reached", date minutesago lte 30)` - 最近 30 分钟内的事件
- `Event("11111-11111", "Level reached", date minutesago gte 60)` - 60 分钟或更久以前的事件

</Aside>

### 事件平台

根据事件触发的平台筛选事件。

*   **platforms** - 平台列表（例如 `["ios", "android"]`）

<Aside type="note" title="事件平台语法示例">
`Event("11111-11111", "Level reached", platforms ["android", "ios"], count gte 5)`
</Aside>

### 事件属性

事件条件可以根据事件属性值进行筛选。属性支持各种数据类型及其相应的运算符。

#### 整数事件属性

*   **attribute "name" eq** - 属性等于指定值
*   **attribute "name" noteq** - 属性不等于指定值
*   **attribute "name" gte** - 属性大于或等于指定值
*   **attribute "name" lte** - 属性小于或等于指定值
*   **attribute "name" between** - 属性在指定范围内
*   **attribute "name" in** - 属性等于任何指定值之一
*   **attribute "name" notin** - 属性不等于任何指定值
*   **attribute "name" any** - 为该属性设置了任何值
*   **attribute "name" notset** - 未为该属性设置值

<Aside type="note" title="整数属性语法示例">

* `Event("11111-11111", "Purchase", attribute "amount" eq 42)`
* `Event("11111-11111", "Purchase", attribute "amount" between 10 100)`
* `Event("11111-11111", "Purchase", attribute "amount" in [10, 20, 30])`

</Aside>

#### 字符串事件属性

*   **attribute "name" eq** - 属性等于指定值
*   **attribute "name" noteq** - 属性不等于指定值
*   **attribute "name" startswith** - 属性以指定前缀开头
*   **attribute "name" endswith** - 属性以指定后缀结尾
*   **attribute "name" contains** - 属性包含指定子字符串
*   **attribute "name" in** - 属性等于任何指定值之一
*   **attribute "name" notin** - 属性不等于任何指定值
*   **attribute "name" any** - 为该属性设置了任何值
*   **attribute "name" notset** - 未为该属性设置值

<Aside type="note" title="字符串属性语法示例">

* `Event("11111-11111", "Page View", attribute "url" startswith "https://example.com")`
* `Event("11111-11111", "Page View", attribute "url" endswith ".html")`
* `Event("11111-11111", "Page View", attribute "url" contains "/products/")`
* `Event("11111-11111", "Button Click", attribute "button_name" in ["submit", "cancel"])`

</Aside>

#### 布尔事件属性

*   **attribute "name" eq** - 属性等于 true 或 false
*   **attribute "name" noteq** - 属性不等于 true 或 false

<Aside type="note" title="布尔属性语法示例">
`Event("11111-11111", "Feature Toggle", attribute "enabled" eq true)`
</Aside>

#### 日期事件属性

*   **attribute "name" eq** - 属性等于指定日期
*   **attribute "name" noteq** - 属性不等于指定日期
*   **attribute "name" gte** - 属性在指定日期之后或当天
*   **attribute "name" lte** - 属性在指定日期之前或当天
*   **attribute "name" between** - 属性在指定日期范围内
*   **attribute "name" in** - 属性等于任何指定日期之一
*   **attribute "name" notin** - 属性不等于任何指定日期
*   **attribute "name" daysago eq/noteq/gte/lte/between** - 属性相对于几天前
*   **attribute "name" daysahead from to** - 属性在从当前日期起的指定天数区间内（区间两端均包含，完整语义请参见上文的日期标签运算符）
*   **attribute "name" minutesago gte/lte** - 属性相对于几分钟前
*   **attribute "name" any** - 为该属性设置了任何值
*   **attribute "name" notset** - 未为该属性设置值

<Aside type="note" title="日期属性语法示例">

* `Event("11111-11111", "Subscription", attribute "start_date" eq "2022-01-01 01:02:03")`
* `Event("11111-11111", "Subscription", attribute "start_date" between "2022-01-01 00:00:00" "2022-12-31 23:59:59")`
* `Event("11111-11111", "Subscription", attribute "start_date" daysago lte 30)` - 最近 30 天内
* `Event("11111-11111", "Subscription", attribute "renewal_at" daysahead 0 30)` - 未来 30 天内的续订
* `Event("11111-11111", "Subscription", attribute "start_date" minutesago gte 60)` - 60 分钟或更久以前

</Aside>

#### 价格事件属性

*   **attribute "name" eq** - 属性等于指定价格值
*   **attribute "name" noteq** - 属性不等于指定价格值
*   **attribute "name" gte** - 属性大于或等于指定价格
*   **attribute "name" lte** - 属性小于或等于指定价格
*   **attribute "name" between** - 属性在指定价格范围内
*   **attribute "name" in** - 属性等于任何指定价格之一
*   **attribute "name" notin** - 属性不等于任何指定价格
*   **attribute "name" any** - 为该属性设置了任何值
*   **attribute "name" notset** - 未为该属性设置值

<Aside type="note" title="价格属性语法示例">
`Event("11111-11111", "Purchase", attribute "total_price" between 10.00 50.00)`
</Aside>

#### 列表事件属性

*   **attribute "name" in** - 属性包含任何指定值
*   **attribute "name" notin** - 属性不包含任何指定值
*   **attribute "name" any** - 为该属性设置了任何值
*   **attribute "name" notset** - 未为该属性设置值

<Aside type="note" title="列表属性语法示例">
`Event("11111-11111", "Cart Update", attribute "product_ids" in ["prod-123", "prod-456"])`
</Aside>

## 其他条件类型

### 地理位置条件

根据指定半径内的地理位置定位设备。

**语法：** `Geo("<app-code>", <latitude>, <longitude>, <range-in-km>)`

<Aside type="note" title="地理位置语法示例">
`Geo("11111-11111", 53.2734, -7.77832031, 100.05)` - 距离坐标点 100.05 公里范围内的设备
</Aside>

### BTTS 条件

根据设备的最佳发送通知时间（一天中的小时，0-23）定位设备。

**运算符：**
*   **any** - 设置了任何最佳发送时间值
*   **eq** - 精确小时匹配
*   **noteq** - 不等于该小时
*   **gte** - 小时大于或等于
*   **lte** - 小时小于或等于

<Aside type="note" title="BTTS 语法示例">

* `BTTS("11111-11111", eq 10)` - 最佳发送时间为 10:00 的设备
* `BTTS("11111-11111", gte 18)` - 最佳发送时间从 18:00 开始的设备
* `BTTS("11111-11111", any)` - 具有任何最佳发送时间值的设备

</Aside>

### 更新条件

根据设备的最后更新时间戳筛选设备。

**运算符：**
*   **gte** - 在指定日期之后或当天更新
*   **lte** - 在指定日期之前或当天更新
*   **between** - 在日期范围内更新

<Aside type="note" title="更新语法示例">

* `Updated("11111-11111", gte "2022-01-01 00:00:00")` - 2022 年 1 月 1 日之后更新的设备
* `Updated("11111-11111", lte "2022-12-31 23:59:59")` - 2022 年 12 月 31 日之前更新的设备
* `Updated("11111-11111", between "2022-01-01 00:00:00" "2022-12-31 23:59:59")` - 2022 年更新的设备

</Aside>

### 细分条件

通过其代码引用另一个筛选器/细分。

<Aside type="note" title="细分语法示例">
`Segment("11111-11111", "22222-22222")` - 引用代码为 "22222-22222" 的筛选器
</Aside>

## 应用程序条件设备存在标志

应用程序条件支持额外的标志来控制设备和令牌的筛选：

*   **with_tokens** - 拥有推送通知令牌的设备
*   **without_tokens** - 没有推送通知令牌的设备
*   **with_devices** - 拥有已注册设备的用户
*   **without_devices** - 没有已注册设备的用户/配置文件

<Aside type="note" title="应用程序标志语法示例">

* `A("11111-11111", ["ios", "android"], [with_tokens])` - 拥有推送令牌的设备
* `A("11111-11111", ["ios", "android"], [without_tokens])` - 没有推送令牌的设备
* `A("11111-11111", [], [with_devices])` - 所有拥有设备记录的设备
* `A("11111-11111", ["ios", "android"], [without_tokens, with_devices])` - 没有令牌但有设备记录的设备

</Aside>

## 筛选表达式示例

<Aside type="note">
编写 JSON 查询时，请确保使用反斜杠 (`\`) 转义引号 (`"`) 和反斜杠 (`\`)。
有关示例请求，请参见 [/exportSegment](/zh/developer/api-reference/segmentation-filters-api/#exportsegment)。
</Aside>

### 基本示例

1.  已安装应用并拥有推送令牌的 iOS 和 Android 设备：

```json
A("11111-11111", ["ios","android"], [with_tokens])
```

2.  已安装应用但没有推送令牌的 iOS 和 Android 设备：

```json
A("11111-11111", ["ios","android"], [without_tokens])
```

3.  已安装应用的 iOS 和 Android 设备，无论它们是否有推送令牌：

```json
A("11111-11111", ["ios","android"], [with_tokens, without_tokens])
```

4.  所有在应用内购买过东西的应用订阅者：

```json
AT("11111-11111", "In-App Purchase", gte, 1)
```

### 高级示例

5.  在过去 7 天内打开过应用的东京用户：

```json
T("City", eq, "Tokyo") * Event("11111-11111", "App Open", date daysago lte 7)
```

6.  在过去 30 天内消费超过 50 美元的用户：

```json
Event("11111-11111", "Purchase", attribute "total_price" gte 50.00, date daysago lte 30)
```

7.  姓名以 "J" 开头或以 "e" 结尾的用户：

```json
T("Name", startswith, "J") + T("Name", endswith, "e")
```

8.  距离纽约 100 公里范围内，近期未购物的活跃 iOS 用户：

```json
A("11111-11111", ["ios"], [with_tokens]) * Geo("11111-11111", 40.7128, -74.0060, 100) \ Event("11111-11111", "Purchase", date daysago lte 30)
```

9.  最佳发送时间在上午 9 点到下午 5 点之间的用户：

```json
BTTS("11111-11111", gte 9) * BTTS("11111-11111", lte 17)
```

10. 在过去一小时内在 Android 或 iOS 上触发了特定事件的用户：

```json
Event("11111-11111", "Button Click", platforms ["android", "ios"], date minutesago lte 60)
```

11. 在过去 3 个月内更新且应用版本为 4.2 或更高的设备：

```json
Updated("11111-11111", gte "2024-07-01 00:00:00") * AT("11111-11111", "App Version", gte, "4.2")
```