> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# DataStore 访问器

> String、DateTime、Array、JSON、URL、IP 和 Geo 访问器，提供 185+ 种方法

DataStore 提供 7 个访问器命名空间，包含 185+ 种用于特定领域操作的方法。

| 访问器 | 方法 | 描述 |
| - | - | - |
| `.str` | 56 | 字符串操作 |
| `.dt` | 42+ | DateTime 操作 |
| `.arr` | 37 | Array 操作 (ClickHouse 特有) |
| `.json` | 13 | JSON 解析 (ClickHouse 特有) |
| `.url` | 15 | URL 解析 (ClickHouse 特有) |
| `.ip` | 9 | IP 地址操作 (ClickHouse 特有) |
| `.geo` | 14 | 地理空间/距离操作 (ClickHouse 特有) |

***

## String 访问器 (`.str`)

支持全部 56 个 pandas `.str` 方法，以及 ClickHouse 字符串函数。

### 大小写转换

| 方法 | ClickHouse | 说明 |
| - | - | - |
| `upper()` | `upper()` | 转为大写 |
| `lower()` | `lower()` | 转为小写 |
| `capitalize()` | `initcap()` | 首字母大写 |
| `title()` | `initcap()` | 标题格式大小写 |
| `swapcase()` | - | 大小写互换 |
| `casefold()` | `lower()` | 大小写折叠 |

```python theme={null}
ds['name_upper'] = ds['name'].str.upper()
ds['name_title'] = ds['name'].str.title()
```

### 长度与大小

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `len()` | `length()` | String 长度 (字节) |
| `char_length()` | `char_length()` | 字符数长度 |

```python theme={null}
ds['name_len'] = ds['name'].str.len()
```

### 子串和切片

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `slice(start, stop)` | `substring()` | 截取子串 |
| `slice_replace()` | - | 替换切片部分 |
| `left(n)` | `left()` | 最左边的 n 个字符 |
| `right(n)` | `right()` | 最右边的 n 个字符 |
| `get(i)` | - | 指定索引处的字符 |

```python theme={null}
ds['first_3'] = ds['name'].str.slice(0, 3)
ds['last_4'] = ds['name'].str.right(4)
```

### 去除空白

| Method | ClickHouse | Description |
| - | - | - |
| `strip()` | `trim()` | 去除空白字符 |
| `lstrip()` | `trimLeft()` | 去除开头的空白字符 |
| `rstrip()` | `trimRight()` | 去除末尾的空白字符 |

```python theme={null}
ds['trimmed'] = ds['text'].str.strip()
```

### 搜索与匹配

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `contains(pat)` | `position()` | 包含子串 |
| `startswith(pat)` | `startsWith()` | 以前缀开头 |
| `endswith(pat)` | `endsWith()` | 以后缀结尾 |
| `find(sub)` | `position()` | 查找位置 |
| `rfind(sub)` | - | 从右侧查找 |
| `index(sub)` | `position()` | 查找，找不到则报错 |
| `rindex(sub)` | - | 从右侧查找，找不到则报错 |
| `match(pat)` | `match()` | 正则匹配 |
| `fullmatch(pat)` | - | 完全正则匹配 |
| `count(pat)` | - | 统计出现次数 |

```python theme={null}
# 包含子串
ds['has_john'] = ds['name'].str.contains('John')

# 正则匹配
ds['valid_email'] = ds['email'].str.match(r'^[\w.-]+@[\w.-]+\.\w+$')
```

### 替换

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `replace(pat, repl)` | `replace()` | 替换匹配项 |
| `replace(pat, repl, regex=True)` | `replaceRegexpAll()` | 正则替换 |
| `removeprefix(prefix)` | - | 移除前缀 |
| `removesuffix(suffix)` | - | 移除后缀 |
| `translate(table)` | - | 字符转换 |

```python theme={null}
ds['cleaned'] = ds['text'].str.replace('\n', ' ')
ds['digits_only'] = ds['phone'].str.replace(r'\D', '', regex=True)
```

### 分割

| Method | ClickHouse | Description |
| - | - | - |
| `split(sep)` | `splitByString()` | 分割为数组 |
| `rsplit(sep)` | - | 从右侧开始分割 |
| `partition(sep)` | - | 分割成 3 部分 |
| `rpartition(sep)` | - | 从右侧分割成 3 部分 |

```python theme={null}
ds['parts'] = ds['path'].str.split('/')
```

### 填充

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `pad(width)` | `leftPad()` | 左侧填充 |
| `ljust(width)` | `rightPad()` | 右对齐 |
| `rjust(width)` | `leftPad()` | 左对齐 |
| `center(width)` | - | 居中 |
| `zfill(width)` | `leftPad(..., '0')` | 零填充 |

```python theme={null}
ds['padded_id'] = ds['id'].astype(str).str.zfill(6)
```

### 字符测试

| 方法 | 说明 |
| - | - |
| `isalpha()` | 全为字母 |
| `isdigit()` | 全为数字 |
| `isalnum()` | 仅包含字母和数字 |
| `isspace()` | 全为空白字符 |
| `isupper()` | 全为大写字母 |
| `islower()` | 全为小写字母 |
| `istitle()` | 标题大小写 |
| `isnumeric()` | 数值字符 |
| `isdecimal()` | 十进制字符 |

```python theme={null}
ds['is_numeric'] = ds['code'].str.isdigit()
```

### 其他

| 方法 | 描述 |
| - | - |
| `repeat(n)` | 重复 n 次 |
| `reverse()` | 反转字符串 |
| `wrap(width)` | 按指定宽度换行 |
| `encode(enc)` | 编码 |
| `decode(enc)` | 解码 |
| `normalize(form)` | Unicode 规范化 |
| `extract(pat)` | 提取正则分组 |
| `extractall(pat)` | 提取所有匹配结果 |
| `cat(sep)` | 拼接所有内容 |
| `get_dummies(sep)` | 虚拟变量 |

***

## DateTime 访问器 (`.dt`)

包含 pandas `.dt` 的 42+ 个方法，以及 ClickHouse 日期时间函数。

### 日期组成部分

| 属性 | ClickHouse | 说明 |
| - | - | - |
| `year` | `toYear()` | 年 |
| `month` | `toMonth()` | 月 (1-12) |
| `day` | `toDayOfMonth()` | 日 (1-31) |
| `hour` | `toHour()` | 小时 (0-23) |
| `minute` | `toMinute()` | 分钟 (0-59) |
| `second` | `toSecond()` | 秒 (0-59) |
| `millisecond` | `toMillisecond()` | 毫秒 |
| `microsecond` | `toMicrosecond()` | 微秒 |
| `quarter` | `toQuarter()` | 季 (1-4) |
| `dayofweek` | `toDayOfWeek()` | 星期几 (0=周一) |
| `dayofyear` | `toDayOfYear()` | 一年中的第几天 |
| `week` | `toWeek()` | 周数 |
| `days_in_month` | - | 当月天数 |

```python theme={null}
ds['year'] = ds['date'].dt.year
ds['month'] = ds['date'].dt.month
ds['day_of_week'] = ds['date'].dt.dayofweek
```

### 截断

| 方法 | ClickHouse | 说明 |
| - | - | - |
| `to_start_of_day()` | `toStartOfDay()` | 当天起始时间 |
| `to_start_of_week()` | `toStartOfWeek()` | 当周起始时间 |
| `to_start_of_month()` | `toStartOfMonth()` | 当月起始时间 |
| `to_start_of_quarter()` | `toStartOfQuarter()` | 当季度起始时间 |
| `to_start_of_year()` | `toStartOfYear()` | 当年起始时间 |
| `to_start_of_hour()` | `toStartOfHour()` | 当前小时起始时间 |
| `to_start_of_minute()` | `toStartOfMinute()` | 当前分钟起始时间 |

```python theme={null}
ds['month_start'] = ds['date'].dt.to_start_of_month()
```

### 算术

| Method | ClickHouse | Description |
| - | - | - |
| `add_years(n)` | `addYears()` | 添加年份 |
| `add_months(n)` | `addMonths()` | 添加月份 |
| `add_weeks(n)` | `addWeeks()` | 添加周数 |
| `add_days(n)` | `addDays()` | 添加天数 |
| `add_hours(n)` | `addHours()` | 添加小时 |
| `add_minutes(n)` | `addMinutes()` | 添加分钟 |
| `add_seconds(n)` | `addSeconds()` | 添加秒数 |
| `subtract_years(n)` | `subtractYears()` | 减少年份 |
| `subtract_months(n)` | `subtractMonths()` | 减少月份 |
| `subtract_days(n)` | `subtractDays()` | 减少天数 |

```python theme={null}
ds['next_month'] = ds['date'].dt.add_months(1)
ds['last_week'] = ds['date'].dt.subtract_weeks(1)
```

### 布尔值检查

| 方法 | 描述 |
| - | - |
| `is_month_start()` | 每月第一天 |
| `is_month_end()` | 每月最后一天 |
| `is_quarter_start()` | 每季度第一天 |
| `is_quarter_end()` | 每季度最后一天 |
| `is_year_start()` | 每年第一天 |
| `is_year_end()` | 每年最后一天 |
| `is_leap_year()` | 闰年 |

```python theme={null}
ds['is_eom'] = ds['date'].dt.is_month_end()
```

### 格式化

| 方法 | ClickHouse | 说明 |
| - | - | - |
| `strftime(fmt)` | `formatDateTime()` | 格式化为字符串 |
| `day_name()` | - | 星期名称 |
| `month_name()` | - | 月份名称 |

```python theme={null}
ds['date_str'] = ds['date'].dt.strftime('%Y-%m-%d')
ds['day_name'] = ds['date'].dt.day_name()
```

### 时区

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `tz_convert(tz)` | `toTimezone()` | 转换时区 |
| `tz_localize(tz)` | - | 指定时区 |

```python theme={null}
ds['utc_time'] = ds['timestamp'].dt.tz_convert('UTC')
```

***

## Array 访问器 (`.arr`)

ClickHouse 特有的数组操作 (共 37 个方法) 。

### 属性

| 属性 | ClickHouse | 描述 |
| - | - | - |
| `length` | `length()` | 数组长度 |
| `size` | `length()` | `length` 的别名 |
| `empty` | `empty()` | 是否为空 |
| `not_empty` | `notEmpty()` | 是否不为空 |

```python theme={null}
ds['tag_count'] = ds['tags'].arr.length
ds['has_tags'] = ds['tags'].arr.not_empty
```

### 元素访问

| 方法 | ClickHouse | 说明 |
| - | - | - |
| `array_first()` | `arrayElement(..., 1)` | 第一个元素 |
| `array_last()` | `arrayElement(..., -1)` | 最后一个元素 |
| `array_element(n)` | `arrayElement()` | 第 N 个元素 |
| `array_slice(off, len)` | `arraySlice()` | 数组切片 |

```python theme={null}
ds['first_tag'] = ds['tags'].arr.array_first()
ds['last_tag'] = ds['tags'].arr.array_last()
```

### 聚合

| Method | ClickHouse | Description |
| - | - | - |
| `array_sum()` | `arraySum()` | 元素总和 |
| `array_avg()` | `arrayAvg()` | 平均值 |
| `array_min()` | `arrayMin()` | 最小值 |
| `array_max()` | `arrayMax()` | 最大值 |
| `array_product()` | `arrayProduct()` | 乘积 |
| `array_uniq()` | `arrayUniq()` | 唯一值数量 |

```python theme={null}
ds['total'] = ds['values'].arr.array_sum()
ds['average'] = ds['values'].arr.array_avg()
```

### 转换

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `array_sort()` | `arraySort()` | 升序排序 |
| `array_reverse_sort()` | `arrayReverseSort()` | 降序排序 |
| `array_reverse()` | `arrayReverse()` | 反转顺序 |
| `array_distinct()` | `arrayDistinct()` | 元素去重 |
| `array_compact()` | `arrayCompact()` | 移除连续重复项 |
| `array_flatten()` | `arrayFlatten()` | 展平嵌套结构 |

```python theme={null}
ds['sorted_tags'] = ds['tags'].arr.array_sort()
ds['unique_tags'] = ds['tags'].arr.array_distinct()
```

### 修改操作

| 方法 | ClickHouse | 说明 |
| - | - | - |
| `array_push_back(elem)` | `arrayPushBack()` | 添加到末尾 |
| `array_push_front(elem)` | `arrayPushFront()` | 添加到开头 |
| `array_pop_back()` | `arrayPopBack()` | 删除最后一个 |
| `array_pop_front()` | `arrayPopFront()` | 删除第一个 |
| `array_concat(other)` | `arrayConcat()` | 连接 |

### 查找

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `has(elem)` | `has()` | 是否包含元素 |
| `index_of(elem)` | `indexOf()` | 查找索引位置 |
| `count_equal(elem)` | `countEqual()` | 统计出现次数 |

```python theme={null}
ds['has_python'] = ds['skills'].arr.has('Python')
```

### String 操作

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `array_string_concat(sep)` | `arrayStringConcat()` | 拼接为字符串 |

```python theme={null}
ds['tags_str'] = ds['tags'].arr.array_string_concat(', ')
```

***

## JSON 访问器 (`.json`)

ClickHouse 特有的 JSON 解析方法 (13 种) 。

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `get_string(path)` | `JSONExtractString()` | 提取字符串 |
| `get_int(path)` | `JSONExtractInt()` | 提取整数 |
| `get_float(path)` | `JSONExtractFloat()` | 提取浮点数 |
| `get_bool(path)` | `JSONExtractBool()` | 提取布尔值 |
| `get_raw(path)` | `JSONExtractRaw()` | 提取原始 JSON |
| `get_keys()` | `JSONExtractKeys()` | 获取键 |
| `get_type(path)` | `JSONType()` | 获取类型 |
| `get_length(path)` | `JSONLength()` | 获取长度 |
| `has_key(key)` | `JSONHas()` | 检查键是否存在 |
| `is_valid()` | `isValidJSON()` | 验证 JSON 是否有效 |
| `to_json_string()` | `toJSONString()` | 转换为 JSON |

```python theme={null}
# 解析 JSON 列
ds['user_name'] = ds['json_data'].json.get_string('user.name')
ds['user_age'] = ds['json_data'].json.get_int('user.age')
ds['is_active'] = ds['json_data'].json.get_bool('user.active')
ds['has_email'] = ds['json_data'].json.has_key('user.email')
```

***

## URL 访问器 (`.url`)

ClickHouse 特有的 URL 解析功能 (15 个方法) 。

| 方法 | ClickHouse | 说明 |
| - | - | - |
| `domain()` | `domain()` | 提取域名 |
| `domain_without_www()` | `domainWithoutWWW()` | 不含 www 的域名 |
| `top_level_domain()` | `topLevelDomain()` | 顶级域名 |
| `protocol()` | `protocol()` | 协议 (http/https) |
| `path()` | `path()` | URL 路径 |
| `path_full()` | `pathFull()` | 包含查询字符串的路径 |
| `query_string()` | `queryString()` | 查询字符串 |
| `fragment()` | `fragment()` | 片段 (#...) |
| `port()` | `port()` | 端口号 |
| `extract_url_parameter(name)` | `extractURLParameter()` | 获取查询参数 |
| `extract_url_parameters()` | `extractURLParameters()` | 所有参数 |
| `cut_url_parameter(name)` | `cutURLParameter()` | 移除参数 |
| `decode_url_component()` | `decodeURLComponent()` | URL 解码 |
| `encode_url_component()` | `encodeURLComponent()` | URL 编码 |

```python theme={null}
# 解析 URL
ds['domain'] = ds['url'].url.domain()
ds['path'] = ds['url'].url.path()
ds['utm_source'] = ds['url'].url.extract_url_parameter('utm_source')
```

***

## IP Accessor (`.ip`)

ClickHouse 特有的 IP 地址操作 (9 个方法) 。

| Method | ClickHouse | Description |
| - | - | - |
| `to_ipv4()` | `toIPv4()` | 转换为 IPv4 |
| `to_ipv6()` | `toIPv6()` | 转换为 IPv6 |
| `ipv4_num_to_string()` | `IPv4NumToString()` | 数值转换为字符串 |
| `ipv4_string_to_num()` | `IPv4StringToNum()` | 字符串转换为数值 |
| `ipv6_num_to_string()` | `IPv6NumToString()` | IPv6 数值转换为字符串 |
| `ipv4_to_ipv6()` | `IPv4ToIPv6()` | 转换为 IPv6 |
| `is_ipv4_string()` | `isIPv4String()` | 校验 IPv4 |
| `is_ipv6_string()` | `isIPv6String()` | 校验 IPv6 |
| `ipv4_cidr_to_range(cidr)` | `IPv4CIDRToRange()` | 将 CIDR 转换为范围 |

```python theme={null}
# IP 操作
ds['is_valid_ip'] = ds['ip'].ip.is_ipv4_string()
ds['ip_num'] = ds['ip'].ip.ipv4_string_to_num()
```

***

## Geo 访问器 (`.geo`)

ClickHouse 特有的 Geo/距离相关操作 (14 个方法) 。

### 距离函数

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `great_circle_distance(...)` | `greatCircleDistance()` | 大圆距离 |
| `geo_distance(...)` | `geoDistance()` | WGS-84 距离 |
| `l1_distance(v1, v2)` | `L1Distance()` | 曼哈顿距离 |
| `l2_distance(v1, v2)` | `L2Distance()` | 欧氏距离 |
| `l2_squared_distance(v1, v2)` | `L2SquaredDistance()` | 欧氏距离的平方 |
| `linf_distance(v1, v2)` | `LinfDistance()` | 切比雪夫距离 |
| `cosine_distance(v1, v2)` | `cosineDistance()` | 余弦距离 |

### 向量运算

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `dot_product(v1, v2)` | `dotProduct()` | 点积 |
| `l2_norm(vec)` | `L2Norm()` | 向量范数 |
| `l2_normalize(vec)` | `L2Normalize()` | 归一化 |

### H3 函数

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `geo_to_h3(lon, lat, res)` | `geoToH3()` | Geo 转为 H3 索引 |
| `h3_to_geo(h3)` | `h3ToGeo()` | H3 转为地理坐标 |

### 点运算

| 方法 | ClickHouse | 描述 |
| - | - | - |
| `point_in_polygon(pt, poly)` | `pointInPolygon()` | 点是否在多边形内 |
| `point_in_ellipses(...)` | `pointInEllipses()` | 点是否在椭圆内 |

```python theme={null}
from chdb.datastore import F

# 计算距离
ds['distance'] = F.great_circle_distance(
    ds['lon1'], ds['lat1'],
    ds['lon2'], ds['lat2']
)

# 向量相似度
ds['similarity'] = F.cosine_distance(ds['embedding1'], ds['embedding2'])
```

***

## 使用 访问器

### 惰性求值

大多数 访问器 方法都采用惰性求值——它们返回的是稍后才会求值的表达式：

```python theme={null}
# 以下这些都是惰性求值
ds['name_upper'] = ds['name'].str.upper()  # 尚未执行
ds['year'] = ds['date'].dt.year            # 尚未执行
ds['domain'] = ds['url'].url.domain()      # 尚未执行

# 访问结果时才会触发执行
df = ds.to_df()  # 此时所有操作才会执行
```

### 立即执行的方法

某些 `.str` 方法必须立即执行，因为它们会更改结构：

| 方法 | 返回 | 原因 |
| - | - | - |
| `partition(sep)` | DataStore (3 列) | 会生成多个列 |
| `rpartition(sep)` | DataStore (3 列) | 会生成多个列 |
| `get_dummies(sep)` | DataStore (N 列) | 列数是动态的 |
| `extractall(pat)` | DataStore | MultiIndex 结果 |
| `cat(sep)` | str | 聚合 (N 行 → 1) |

### 访问器 的链式调用

访问器 方法可以进行链式调用：

```python theme={null}
ds['clean_name'] = (ds['name']
    .str.strip()
    .str.lower()
    .str.replace(' ', '_')
)

ds['next_month_start'] = (ds['date']
    .dt.add_months(1)
    .dt.to_start_of_month()
)
```
