Metadata-Version: 2.4
Name: LangSC
Version: 2.0.7
Summary: Language Structure Computation - GPF, BCC, and JSS unified package
Author: endongxun
Author-email: xunendong@gmail.com
License: MIT
Classifier: Development Status :: 5 - Production/Stable
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pywin32; platform_system == "Windows"
Requires-Dist: wordcloud
Requires-Dist: requests
Requires-Dist: chardet
Dynamic: license-file

# LangSC 使用手册

**LangSC**（Language Structure Computation）是一个统一的 Python 开发包，集成了自然语言结构分析（GPF）、语料库查询（BCC）和 JSON 结构检索（JSS）三大功能。

当前版本：**1.0.6**

---

## 目录

- [1. 概述](#1-概述)
- [2. 安装与配置](#2-安装与配置)
- [3. 快速上手](#3-快速上手)
- [4. GPF 类 — 自然语言结构分析](#4-gpf-类--自然语言结构分析)
  - [4.1 构造函数](#41-构造函数)
  - [4.2 自动索引机制](#42-自动索引机制)
  - [4.3 NLP 分析](#43-nlp-分析)
  - [4.4 文本与网格操作](#44-文本与网格操作)
  - [4.5 Unit 操作](#45-unit-操作)
  - [4.6 Relation 操作](#46-relation-操作)
  - [4.7 Grid KV 操作](#47-grid-kv-操作)
  - [4.8 Table 操作](#48-table-操作)
  - [4.9 FSA 操作](#49-fsa-操作)
  - [4.10 索引创建](#410-索引创建)
  - [4.11 结构添加](#411-结构添加)
  - [4.12 可视化](#412-可视化)
  - [4.13 服务调用与 Dot](#413-服务调用与-dot)
  - [4.14 其他方法](#414-其他方法)
  - [4.15 GPF 方法速查表](#415-gpf-方法速查表)
- [5. BCC 类 — 语料库查询](#5-bcc-类--语料库查询)
  - [5.1 构造函数](#51-构造函数)
  - [5.2 自动索引机制](#52-自动索引机制)
  - [5.3 语料查询](#53-语料查询)
  - [5.4 KV 操作](#54-kv-操作)
  - [5.5 语料索引](#55-语料索引)
  - [5.6 BCC 方法速查表](#56-bcc-方法速查表)
- [6. JSS 类 — JSON 结构检索](#6-jss-类--json-结构检索)
  - [6.1 构造函数](#61-构造函数)
  - [6.2 自动索引机制](#62-自动索引机制)
  - [6.3 数据目录结构](#63-数据目录结构)
  - [6.4 cfg 配置文件](#64-cfg-配置文件)
  - [6.5 cfg 自动生成规则](#65-cfg-自动生成规则)
  - [6.6 查询](#66-查询)
  - [6.7 资源释放](#67-资源释放)
  - [6.8 JSS 方法速查表](#68-jss-方法速查表)
- [7. 完整示例](#7-完整示例)
- [8. 数据文件格式说明](#8-数据文件格式说明)
- [9. 平台与依赖](#9-平台与依赖)
- [10. 参考文献](#10-参考文献)

---

## 1. 概述

LangSC 包含三个相互独立的核心类：

| 类 | 功能 | 底层库 | 索引日志 |
|---|------|--------|----------|
| **GPF** | 基于网格（Lattice/Grid）的自然语言结构分析框架，支持分词、词性标注、句法分析、FSA 规则匹配、数据表查询和可视化 | `gpflib` | `IdxLog_GPF.txt` |
| **BCC** | 语料库查询引擎，支持词频统计、上下文检索、计数查询和语料索引 | `bcclib` | `IdxLog_BCC.txt` |
| **JSS** | JSON 结构化数据检索引擎，支持 SQL 风格查询、多表管理和自动建索引 | `jsslib` | `IdxLog_JSS.txt` |

三个类**相互独立**，按需导入即可，不会加载多余的动态库。例如只使用 JSS 时，不会加载 `gpflib` 和 `bcclib`。

### 架构设计

```
LangSC/
├── __init__.py          # 导出 GPF, BCC, JSS, __version__
├── __version__.py       # 版本号（VERSION = (1, 0, 6)）
├── _utils.py            # 共享工具函数（编码检测、索引日志管理等）
├── gpf.py               # GPF 类（封装 gpflib）
├── bcc.py               # BCC 类（封装 bcclib）
├── jss.py               # JSS 类（封装 jsslib）
├── gpflib.dll / libgpflib.so / libgpflib.dylib
├── bcclib.dll / libbcclib.so / libbcclib.dylib
├── jsslib.dll / libjsslib.so / libjsslib.dylib
├── GPFconfig.txt        # GPF 引擎配置
├── BCCconfig.txt        # BCC 引擎配置
├── Parser.lua           # Lua 查询解析脚本
├── Segment.dat          # CRF 分词模型
├── idxPOS.dat           # 词性标注数据
├── base.lex             # 分词词典（JSS 用）
└── Graph/               # Graphviz 工具（Windows 下自带 dot.exe）
```

---

## 2. 安装与配置

### 2.1 安装

```bash
pip install LangSC
```

### 2.2 依赖

| 依赖包 | 用途 | 说明 |
|--------|------|------|
| `pywin32` | Windows DLL 内存释放 | 仅 Windows 平台自动安装 |
| `wordcloud` | 词云可视化 | GPF 的 `ShowCloud` 方法使用 |
| `requests` | HTTP 请求 | GPF 远程句法分析和 Dot 服务使用 |
| `chardet` | 文件编码自动检测 | 全部三个类的文件编码检测使用 |

### 2.3 系统要求

- **Python** >= 3.6
- **操作系统**：Windows、Linux、macOS

### 2.4 版本查询

```python
import LangSC
print(LangSC.__version__)  # "1.0.6"
```

---

## 3. 快速上手

### GPF：句法分析与可视化

```python
from LangSC import GPF
import json

gpf = GPF()

# 句法树分析（远程服务）
text = "中欧班列持续稳定开行，夯实了亚欧大陆互联互通的基础"
js = gpf.Parse(text, Structure="Tree")
gpf.ShowStructure(js, "Dep.png")
```

### BCC：语料库查询

```python
from LangSC import BCC

bcc = BCC("Corpus")
ret = bcc.Run("喜欢{}", Command="Context", PageNo=0, WinSize=30, Number=10)
print(ret)
```

### JSS：JSON 数据检索

```python
from LangSC import JSS

jss = JSS("json")
ret = jss.Run('SELECT * FROM pinyin WHERE PinYin ="da1"')
print(ret)
```

---

## 4. GPF 类 — 自然语言结构分析

GPF（Grid-based Parsing Framework）提供基于网格的自然语言结构分析能力。核心数据结构是**网格（Grid/Lattice）**，其中包含**语言单元（Unit）**和**关系（Relation）**，支持文本分析、规则匹配、词表查询和结构可视化。

### 4.1 构造函数

```python
from LangSC import GPF

gpf = GPF(dataPath="./data")
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `dataPath` | `str` | `"./data"` | 数据目录路径，包含 Table 和 FSA 文件 |

**说明**
- 构造时自动初始化 GPF 网格句柄和 CRF/POS 句柄
- 自动加载 CRF 分词模型（`Segment.dat`）和词性标注数据（`idxPOS.dat`）
- 自动检测数据目录状态并执行索引（详见 [4.2](#42-自动索引机制)）
- `dataPath` 中的反斜杠会自动转换为正斜杠

### 4.2 自动索引机制

构造函数调用 `_init_gpf_data(dataPath)` 自动处理数据索引：

1. 检查 `dataPath` 中是否存在 `IdxLog_GPF.txt` 索引日志
2. **若存在**：已是索引目录，直接使用
3. **若不存在**：视为原始数据目录
   - 扫描目录下的 Table 和 FSA 文件
   - 创建 `dataPathIdx/` 索引目录
   - 逐一索引 Table 和 FSA 文件，并记录到 `IdxLog_GPF.txt`
4. 通过文件时间戳比较，避免重复索引

> 索引完成后，`self.dataPath` 指向实际的索引目录路径。

### 4.3 NLP 分析

#### `Segment(text, table="")`

对文本执行 CRF 分词。

```python
result = gpf.Segment("自然语言处理是人工智能的重要方向")
# 返回: "自然 语言 处理 是 人工 智能 的 重要 方向"
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `text` | `str` | （必填） | 待分词文本 |
| `table` | `str` | `""` | 用户词表名称。为空使用 CRF 模型分词；指定时使用用户词表辅助分词 |

**返回值**：`str`，以空格分隔的分词结果。

#### `POS(text, table="")`

对文本执行词性标注（先分词，再标注）。

```python
result = gpf.POS("自然语言处理是人工智能的重要方向")
# 返回: "自然/b 语言/n 处理/v 是/v 人工/b 智能/n 的/u 重要/a 方向/n"
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `text` | `str` | （必填） | 待标注文本 |
| `table` | `str` | `""` | 用户词表名称 |

**返回值**：`str`，格式为 `词/词性` 以空格分隔。

#### `Parse(text, **Others)`

统一解析接口，根据 `Structure` 参数调用不同的解析方式。

```python
# 分词
result = gpf.Parse("自然语言处理", Structure="Segment")

# 词性标注（默认）
result = gpf.Parse("自然语言处理", Structure="POS")

# 句法树（远程服务 https://cit.blcu.edu.cn/stree）
result = gpf.Parse("自然语言处理", Structure="Tree")

# 短语分析（远程服务 https://cit.blcu.edu.cn/chunk/）
result = gpf.Parse("自然语言处理", Structure="Chunk")

# 依存分析（远程服务 https://cit.blcu.edu.cn/dep）
result = gpf.Parse("自然语言处理", Structure="Dep")

# 指定用户词表
result = gpf.Parse("自然语言处理", Structure="Segment", Table="myDict")

# 通过 Web 服务解析
result = gpf.Parse("自然语言处理", Structure="POS", Web=True)
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `text` | `str` | （必填） | 待解析文本（自动截断至 1024 字符） |
| `Structure` | `str` | `"POS"` | 解析类型：`"Segment"` / `"POS"` / `"Tree"` / `"Chunk"` / `"Dep"` |
| `Web` / `IsWeb` | `bool` | `False` | 是否通过 Web 服务解析 |
| `Table` | `str` | `""` | 用户词表名称 |

**返回值**：`str`，JSON 格式字符串。
- `Segment`：`["词1", "词2", ...]`
- `POS`：`["词1/POS1", "词2/POS2", ...]`
- `Tree` / `Chunk` / `Dep`：远程服务返回的 JSON 结构

**示例**（Demo/GPF2.py）：

```python
from LangSC import GPF
import json

gpf = GPF()
Txt = "中欧班列持续稳定开行，夯实了亚欧大陆互联互通的基础"
js = gpf.Parse(Txt, Structure="Tree")
gpf.ShowStructure(js, "Dep.png")
```

### 4.4 文本与网格操作

GPF 的核心数据结构是**网格（Grid）**，网格承载文本、Unit 和 Relation。

#### `SetText(text)` / `SetGridText(text)`

设置网格的文本内容。`SetGridText` 额外执行 `GPFInit()` 初始化。

```python
gpf.SetText("今天天气很好")
gpf.SetGridText("今天天气很好")  # 等价，额外调用 GPFInit
```

**返回值**：`int`，操作状态码。

#### `GetText(begin=0, end=-1)` / `GetGridText(begin=0, end=-1)`

获取网格中的文本。

```python
text = gpf.GetText()           # 获取全部文本
text = gpf.GetText(0, 3)       # 获取位置 0 到 3 的文本
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `begin` | `int` | `0` | 起始位置 |
| `end` | `int` | `-1` | 结束位置（`-1` 表示全部） |

**返回值**：`str`。

#### `GetGrid()` / `GetStructure()`

获取完整的网格结构。

```python
grid = gpf.GetGrid()
```

**返回值**：`list`，网格结构的 JSON 对象。网格为空时返回 `{}`。

网格是一个二维结构，返回值为列（Column）的列表，每列包含若干 Unit 编号。

### 4.5 Unit 操作

Unit 是网格中的基本语言单元，对应一个词或短语，具有位置信息和键值属性。Unit 编号的格式为 `"(起始位置,结束位置)"`，如 `"(0,2)"`。

#### `AddUnit(text, colNo=-1)`

向网格添加 Unit。

```python
unitNo = gpf.AddUnit("天气")           # 自动定位
unitNo = gpf.AddUnit("天气", colNo=3)  # 指定结束位置（字符位置）
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `text` | `str` | （必填） | Unit 的文本内容 |
| `colNo` | `int` | `-1` | 结束字符位置。`-1` 时自动查找文本位置 |

**返回值**：`str`，Unit 编号（如 `"(0,2)"`）。

**示例**（Demo/GPF4.py）：

```python
from LangSC import GPF

gpf = GPF()
Text = "孩子们都吃撑了"
gpf.SetText(Text)
Child = gpf.AddUnit("孩子们", 2)
All = gpf.AddUnit("都", 3)
Eat = gpf.AddUnit("吃", 4)
Full = gpf.AddUnit("撑了", 6)
```

#### `AddUnitKV(unitNo, key, val)`

为 Unit 添加键值属性。

```python
gpf.AddUnitKV(unitNo, "POS", "n")           # 添加词性
gpf.AddUnitKV(unitNo, "Tag", "人名;地名")    # 多值用分隔符
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `unitNo` | `str` | Unit 编号 |
| `key` | `str` | 属性名 |
| `val` | `str` | 属性值。支持以空格、分号、逗号、制表符分隔的多值，每个值分别添加 |

**返回值**：`int`，固定返回 `1`。

#### `GetWord(unitNo)`

获取 Unit 的文本内容。

```python
word = gpf.GetWord(unitNo)  # 例如 "天气"
```

**返回值**：`str`。

#### `GetUnit(kv, UnitNo="", UExpress="")`

按条件查找 Unit。当参数为整数时，按 FSA 路径号获取。

```python
units = gpf.GetUnit("POS=n")           # 查找所有词性为 n 的 Unit
unit  = gpf.GetUnit(0)                 # 按 FSA 路径号获取（整数参数）
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `kv` | `str` 或 `int` | （必填） | 查询条件（如 `"POS=n"`）或 FSA 路径号 |
| `UnitNo` | `str` | `""` | 限定在某个 Unit 范围内查找 |
| `UExpress` | `str` | `""` | Unit 表达式 |

**返回值**：条件查找时返回 `list` / `dict`（无匹配返回 `0`）；路径号查找时返回 `str`。

#### `GetUnitKV(unitNo, key="")`

获取 Unit 的属性值。别名：`GetUnitKVs`。

```python
kvs  = gpf.GetUnitKV(unitNo)              # 获取全部属性 → dict
word = gpf.GetUnitKV(unitNo, "Word")      # 获取文本 → str
pos  = gpf.GetUnitKV(unitNo, "From")      # 获取起始位置 → int
vals = gpf.GetUnitKV(unitNo, "POS")       # 获取指定属性 → list
```

**返回值**：

| `key` 值 | 返回类型 | 说明 |
|-----------|----------|------|
| `""` | `dict` | 全部属性键值对 |
| `"Word"` / `"HeadWord"` | `str` | 文本（无匹配返回 `""`） |
| `"From"` / `"To"` | `int` | 位置（无匹配返回 `-1`） |
| 其他 | `list` | 属性值列表 |

#### `IsUnit(unitNo, kv)`

判断 Unit 是否具有指定属性。

```python
ret = gpf.IsUnit(unitNo, "POS=n")       # 判断词性是否为 n
ret = gpf.IsUnit(unitNo, "Type=Word")   # 判断类型
```

**返回值**：`int`，匹配返回非零值，不匹配返回 `0`。

### 4.6 Relation 操作

Relation 表示两个 Unit 之间的有向关系（如主谓、动宾等）。

#### `AddRelation(unitNo1, unitNo2, role)`

添加关系。

```python
gpf.AddRelation(Eat, Child, "sbj")   # 吃 → 孩子们，关系为 sbj（主语）
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `unitNo1` | `str` | 源 Unit 编号 |
| `unitNo2` | `str` | 目标 Unit 编号 |
| `role` | `str` | 关系类型 |

**返回值**：`int`，固定返回 `1`。

#### `AddRelationKV(unitNo1, unitNo2, role, key, val)`

为关系添加键值属性。

```python
gpf.AddRelationKV(Full, Child, "sbj", "K1", "V1")
```

**返回值**：`int`，固定返回 `1`。

#### `GetRelation(kv="")` / `GetRelations(kv="")`

获取关系列表。

```python
rels = gpf.GetRelation()            # 获取全部关系
```

**返回值**：`list`，每个元素为 `[unitNo1, unitNo2, role]` 三元组。无关系返回 `[]`。

#### `GetRelationKV(unitNo1, unitNo2, role, key="")`

获取关系属性。别名：`GetRelationKVs`。

```python
kvs = gpf.GetRelationKV(r[0], r[1], r[2])       # 全部属性
kvs = gpf.GetRelationKV(r[0], r[1], r[2], "K1")  # 指定属性
```

**返回值**：`dict`。

#### `IsRelation(unitNo1, unitNo2, role, kv="")`

判断两个 Unit 之间是否存在指定关系。

```python
ret = gpf.IsRelation(unitNo1, unitNo2, "sbj")
```

**返回值**：`int`，存在返回非零值。

**示例**（Demo/GPF4.py）：

```python
from LangSC import GPF

gpf = GPF()
Text = "孩子们都吃撑了"
gpf.SetText(Text)
Child = gpf.AddUnit("孩子们", 2)
All = gpf.AddUnit("都", 3)
Eat = gpf.AddUnit("吃", 4)
Full = gpf.AddUnit("撑了", 6)

gpf.AddUnitKV(Eat, "POS", "V")
gpf.AddUnitKV(Full, "POS", "V")

gpf.AddRelation(Eat, All, "mod")
gpf.AddRelation(Eat, Full, "mod")
gpf.AddRelation(Eat, Child, "sbj")
gpf.AddRelation(Full, Child, "sbj")
gpf.AddRelationKV(Full, Child, "sbj", "K1", "V1")

R = gpf.GetRelation()
for r in R:
    print(r)
    print(gpf.GetUnitKV(r[0], "Word"), gpf.GetUnitKV(r[1], "Word"), r[2])
    KVs = gpf.GetRelationKV(r[0], r[1], r[2])
    for K, Vs in KVs.items():
        print(K)
```

### 4.7 Grid KV 操作

为整个网格（而非某个 Unit）添加/获取全局属性。

#### `AddGridKV(key, val)` / `AddTextKV(key, val)`

添加网格级属性。

```python
gpf.AddGridKV("Author", "张三")
gpf.AddGridKV("URoot", unitNo)   # 设置根节点
```

**返回值**：`int`，固定返回 `0`。

#### `GetGridKV(key="")` / `GetGridKVs(key="")` / `GetTextKV(key="")`

获取网格级属性。

```python
kvs = gpf.GetGridKV()           # 全部属性
kvs = gpf.GetGridKV("Author")   # 指定属性
```

**返回值**：`dict` / `list`。

### 4.8 Table 操作

Table 是 GPF 的词表/数据表系统，支持键值查询、前后缀匹配等操作。Table 文件以 `Table <表名>` 开头（格式见 [8.1](#81-gpf-table-文件格式)）。

#### `SetTable(tableName)`

设置当前活跃的数据表。

```python
gpf.SetTable("CiDian")
```

#### `CallTable(tableName, Mode=0)`

加载并设置数据表。内部先调用 `GPF_AppLexicon` 加载，再调用 `GPF_SetLexicon` 设为当前表。

```python
gpf.CallTable("CiDian")
```

#### `GetTable()`

获取所有已加载的表名。

```python
tables = gpf.GetTable()
```

**返回值**：`dict`。

#### `GetTableItem(tableName="", kv="")` / `GetItem(tableName="", kv="")`

获取表中的条目列表。

```python
items = gpf.GetTableItem("CiDian")           # 全部条目
items = gpf.GetTableItem("CiDian", "POS=n")  # 按条件过滤
```

#### `GetTableItems(tableName, kv="")`

获取指定表的条目列表。

```python
items = gpf.GetTableItems("CiDian", "POS=n")
```

**返回值**：`dict` / `list`。

#### `GetTableItemKV(tableName, item="", key="")` / `GetItemKV(...)` / `GetTableItemKVs(...)`

获取表中某条目的属性。

```python
kvs = gpf.GetTableItemKV("CiDian", "天气")               # 全部属性
kvs = gpf.GetTableItemKVs("CiDian", "天气", "POS")        # 指定属性
```

**返回值**：`dict` / `list`。

#### `IsTable(tableName, item="", kv="")`

判断表/条目/属性是否存在。

```python
ret = gpf.IsTable("CiDian")                        # 判断表是否存在
ret = gpf.IsTable("CiDian", "天气")                # 判断条目是否存在
ret = gpf.IsTable("CiDian", "天气", "POS=n")       # 判断属性是否匹配
```

**返回值**：`int`，存在返回非零值。

#### `GetSuffix(tableName, sentence)` / `GetPrefix(tableName, sentence)`

后缀/前缀匹配。

```python
suffix = gpf.GetSuffix("CiDian", "今天天气很好")
prefix = gpf.GetPrefix("CiDian", "今天天气很好")
```

**返回值**：`str`。

### 4.9 FSA 操作

FSA 是 GPF 的规则引擎，支持基于有限状态自动机的模式匹配和规则执行。

#### `CallFSA(fsaName, **Others)` / `RunFSA(fsaName, param="")`

执行 FSA 规则。关键字参数自动拼接为 `"Key1=Val1;Key2=Val2"` 格式传入。

```python
gpf.CallFSA("myRule", Param1="val1", Param2="val2")
gpf.RunFSA("myRule")  # 等价于 CallFSA("myRule")
```

**返回值**：`int`，FSA 执行结果长度。

**说明**：FSA 匹配成功后，会通过 `exec()` 执行规则中嵌入的 Python 代码。

#### `GetFSAParam(key)` / `GetParam(key)`

获取 FSA 参数。

```python
val = gpf.GetParam("Result")
```

**返回值**：`str`。

#### `GetFSANode(tag="-1")` / `GetNode(tag)`

获取 FSA 节点。

```python
pathNo = gpf.GetNode(0)  # 支持整数和字符串参数
```

**返回值**：`int`，路径号。

### 4.10 索引创建

#### `IndexTable(table_filename)`

索引 Table 文件。索引后自动重新加载配置。若存在搭配关系（Collocation），会递归索引搭配表。

```python
gpf.IndexTable("./data/myTable.txt")
```

**返回值**：若存在搭配信息返回 `dict`，否则返回 `0`。

#### `IndexFSA(rule_filename)`

索引 FSA 规则文件。索引后自动重新加载配置。

```python
gpf.IndexFSA("./data/myRule.txt")
```

**返回值**：`int`，操作状态码。

### 4.11 结构添加

将 JSON 格式的语言结构数据添加到当前网格中。

#### `AddStructure(json_str)` / `AddGrid(json_str)` / `AddGridJS(json_str)`

添加结构，自动识别类型：

- 若 JSON 包含 `"Type"` 字段：直接调用底层 `GPF_AddStructure`
- 否则根据 JSON 结构自动识别为 Graph / Seq / Tree

```python
gpf.AddStructure(json_str)
```

#### `AddSeq(json_str)`

添加序列结构（分词/词性结果）。

```python
# 字符串列表
gpf.AddSeq('["自然/b", "语言/n", "处理/v"]')

# 字典列表（带属性）
gpf.AddSeq('[{"自然": {"POS": "b"}}, {"语言": {"POS": "n"}}]')
```

**示例**（Demo/GPF5.py）：

```python
from LangSC import GPF

gpf = GPF()
Text = "我们大家很辛苦"
gpf.SetText(Text)
gpf.AddStructure('["我们","大家","很","辛苦"]')
gpf.AddStructure('["我们","大家","很辛苦"]')
gpf.ShowGrid()
Grid = gpf.GetGrid()
for Col in Grid:
    for Unit in Col:
        print(Unit, gpf.GetUnitKV(Unit, "Word"))
```

#### `AddTree(json_str)`

添加树结构。

```python
gpf.AddTree('{"S": ["NP", {"VP": ["V", "NP"]}]}')
```

#### `AddGraph(json_str)`

添加图结构。

```python
# 三元组列表：[源, 目标, 关系]
gpf.AddGraph('[["喜欢", "我", "SBJ"], ["喜欢", "北京", "OBJ"]]')

# 字典格式：{源: {关系: 目标}}
gpf.AddGraph('{"喜欢": {"SBJ": "我", "OBJ": "北京"}}')
```

### 4.12 可视化

GPF 提供多种可视化方法，通过 Graphviz 的 `dot` 工具生成 PNG 图片。

#### `Show(Json="", **Others)`

统一可视化接口。

```python
gpf.Show()                                  # 显示当前网格
gpf.Show(Json=json_str)                     # 显示 JSON 结构
gpf.Show(Output="output.png")               # 指定输出文件
gpf.Show(Relation=True)                     # 显示关系
gpf.Show(Grid=False, Relation=True)         # 只显示关系
gpf.Show(Unit=unitNo)                       # 显示单个 Unit 详情
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `Json` | `str` | `""` | JSON 结构数据 |
| `Output` | `str` | `"./gpf.png"` | 输出图片路径 |
| `Relation` / `IsShowRelation` | `bool` | `False` | 是否显示关系 |
| `Grid` / `IsShowGrid` | `bool` | `True` | 是否显示网格 |
| `Unit` | `str` | `""` | 显示指定 Unit 的详情 |

#### `ShowStructure(Json="", Img="./gpf.png")`

显示结构，自动识别类型（Graph / Seq / Tree / Set / GPFStruct）并调用对应方法。

```python
gpf.ShowStructure(json_str, "output.png")
```

#### `ShowGrid(Img="./gpf.png", IsShowRel=False, IsShowGrid=True)`

显示网格结构。Unit 按类型着色：

| 类型 | 颜色 |
|------|------|
| `Type=Char` | 灰色 |
| `Type=Word` | 绿色 |
| `Type=Phrase` | 浅蓝色 |
| `Type=Chunk` | 金色 |

```python
gpf.ShowGrid("output.png")                                            # 仅网格
gpf.ShowGrid("output.png", IsShowRel=True)                            # 网格 + 关系
gpf.ShowGrid("output.png", IsShowRel=True, IsShowGrid=False)          # 仅关系
```

#### `ShowRelation(Img="./gpf.png")`

显示关系图。等价于 `ShowGrid(Img, IsShowRel=True, IsShowGrid=True)`。

```python
gpf.ShowRelation("relations.png")
```

**示例**（Demo/GPF3.py）：

```python
from LangSC import GPF
import json

Line = """
{"Words": ["瑞士", "率先", "破门", "，", "沙其理", "梅开二度", "。"],
"Tags": ["ns", "d", "v", "w", "nr", "i", "w"],
"Relations": [{"U1": 2, "U2":0,"R":"A0","KV":"KV1"},
{"U1": 2, "U2":1,"R":"Mod","KV":"KV2"},
{"U1": 5, "U2":4,"R":"A0","KV":"KV3"}]}"""

S = json.loads(Line)
Txt = "".join(S["Words"])
gpf = GPF()
gpf.SetText(Txt)
ColNo = 0
Units = []
for i in range(len(S["Words"])):
    UnitNo = gpf.AddUnit(S["Words"][i], ColNo + len(S["Words"][i]) - 1)
    Units.append(UnitNo)
    gpf.AddUnitKV(UnitNo, "POS", S["Tags"][i])
    ColNo += len(S["Words"][i])

for R in S["Relations"]:
    gpf.AddRelation(Units[R["U1"]], Units[R["U2"]], R["R"])

gpf.ShowRelation("r.png")
```

#### `ShowUnit(Unit, Img="./gpf.png")`

显示单个 Unit 的属性详情图。

```python
gpf.ShowUnit(unitNo, "unit_detail.png")
```

#### `ShowTree(Json)` / `ShowSeq(Json)` / `ShowGraph(Json)`

返回 Graphviz DOT 脚本字符串（不直接生成文件）。

```python
dot = gpf.ShowTree(json_str)    # 树结构 DOT（自上而下）
dot = gpf.ShowSeq(json_str)     # 序列结构 DOT（从左到右）
dot = gpf.ShowGraph(json_str)   # 图结构 DOT
```

**返回值**：`str`，DOT 脚本。

#### `ShowCloud(Json, Output)`

生成词云图片。

```python
gpf.ShowCloud('{"自然": 10, "语言": 8, "处理": 6}', "cloud.png")
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `Json` | `str` | JSON 格式词频数据 `{"词": 频率, ...}` |
| `Output` | `str` | 输出图片路径 |

### 4.13 服务调用与 Dot

#### `CallService(sentence, name)`

调用远程服务进行文本解析。

```python
result = gpf.CallService("自然语言处理", "Tree")
```

**返回值**：`str`，JSON 字符串。

#### `Dot2Img(Dot, name)`

将 Dot 脚本转换为图片（通过 DLL）。

**返回值**：`bytes`，图片数据。

#### `DotFile(dot_filename, img_filename)`

将 Dot 文件通过远程服务转换为图片文件。

**返回值**：`bool`。

#### `DotBuff(dot_data, img_filename)`

将 Dot 字符串通过远程服务转换为图片文件。

**返回值**：`bool`。

### 4.14 其他方法

#### `GetLog()`

获取 GPF 日志。

**返回值**：`dict`。

#### `Reduce(From=0, To=-1, Head=-1)`

归约操作，将指定范围的 Unit 归约为一个新 Unit。

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `From` | `int` | `0` | 归约起始位置 |
| `To` | `int` | `-1` | 归约结束位置 |
| `Head` | `int` | `-1` | 中心词的 FSA 路径号 |

**返回值**：`str`，新 Unit 编号。

#### `GPFInit()`

手动初始化 GPF 数据（线程安全）。通常无需显式调用。

### 4.15 GPF 方法速查表

| 分类 | 方法 | 说明 |
|------|------|------|
| **NLP** | `Segment(text, table)` | CRF 分词 |
| | `POS(text, table)` | 词性标注 |
| | `Parse(text, **Others)` | 统一解析接口 |
| **文本/网格** | `SetText(text)` / `SetGridText(text)` | 设置文本 |
| | `GetText(begin, end)` / `GetGridText(begin, end)` | 获取文本 |
| | `GetGrid()` / `GetStructure()` | 获取网格 |
| **Unit** | `AddUnit(text, colNo)` | 添加 Unit |
| | `AddUnitKV(unitNo, key, val)` | 添加 Unit 属性 |
| | `GetWord(unitNo)` | 获取 Unit 文本 |
| | `GetUnit(kv, UnitNo, UExpress)` | 查找 Unit |
| | `GetUnitKV(unitNo, key)` | 获取 Unit 属性 |
| | `IsUnit(unitNo, kv)` | 判断 Unit 属性 |
| **Relation** | `AddRelation(u1, u2, role)` | 添加关系 |
| | `AddRelationKV(u1, u2, role, key, val)` | 添加关系属性 |
| | `GetRelation(kv)` | 获取关系列表 |
| | `GetRelationKV(u1, u2, role, key)` | 获取关系属性 |
| | `IsRelation(u1, u2, role, kv)` | 判断关系 |
| **Grid KV** | `AddGridKV(key, val)` / `AddTextKV(key, val)` | 添加网格属性 |
| | `GetGridKV(key)` / `GetTextKV(key)` | 获取网格属性 |
| **Table** | `SetTable(tableName)` | 设置当前表 |
| | `CallTable(tableName)` | 加载并设置表 |
| | `GetTable()` | 获取所有表名 |
| | `GetTableItem(tableName, kv)` / `GetItem(...)` | 获取表条目 |
| | `GetTableItemKV(...)` / `GetItemKV(...)` | 获取条目属性 |
| | `IsTable(tableName, item, kv)` | 判断表/条目/属性 |
| | `GetSuffix(tableName, sentence)` | 后缀匹配 |
| | `GetPrefix(tableName, sentence)` | 前缀匹配 |
| **FSA** | `CallFSA(fsaName, **Others)` / `RunFSA(fsaName)` | 执行 FSA |
| | `GetParam(key)` / `GetFSAParam(key)` | 获取 FSA 参数 |
| | `GetNode(tag)` / `GetFSANode(tag)` | 获取 FSA 节点 |
| **索引** | `IndexTable(filename)` | 索引 Table 文件 |
| | `IndexFSA(filename)` | 索引 FSA 文件 |
| **结构添加** | `AddStructure(json)` / `AddGrid(json)` | 添加结构（自动识别类型） |
| | `AddSeq(json)` | 添加序列 |
| | `AddTree(json)` | 添加树 |
| | `AddGraph(json)` | 添加图 |
| **可视化** | `Show(Json, **Others)` | 统一可视化 |
| | `ShowStructure(Json, Img)` | 显示结构 |
| | `ShowGrid(Img, IsShowRel, IsShowGrid)` | 显示网格 |
| | `ShowUnit(Unit, Img)` | 显示 Unit 详情 |
| | `ShowRelation(Img)` | 显示关系图 |
| | `ShowTree(Json)` / `ShowSeq(Json)` / `ShowGraph(Json)` | 返回 DOT 脚本 |
| | `ShowCloud(Json, Output)` | 词云 |
| **服务** | `CallService(sentence, name)` | 调用远程服务 |
| | `Dot2Img(dot, name)` | Dot 转图片 |
| | `DotFile(dot_file, img_file)` | Dot 文件转图片 |
| | `DotBuff(dot_data, img_file)` | Dot 字符串转图片 |
| **其他** | `GetLog()` | 获取日志 |
| | `Reduce(From, To, Head)` | 归约操作 |
| | `GPFInit()` | 手动初始化 |

---

## 5. BCC 类 — 语料库查询

BCC 提供语料库查询功能，支持词频统计、上下文检索和语料索引。

### 5.1 构造函数

```python
from LangSC import BCC

bcc = BCC(dataPath="./data")
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `dataPath` | `str` | `"./data"` | 语料数据目录路径 |

**说明**
- 自动加载 `bcclib` 动态库
- 自动加载配置文件（`BCCconfig.txt`）和 Lua 解析脚本（`Parser.lua`）
- 自动检测并索引语料数据（详见 [5.2](#52-自动索引机制)）

### 5.2 自动索引机制

构造函数调用 `_init_bcc_data(dataPath)` 自动处理语料索引：

1. 检查 `dataPath` 中是否存在 `IdxLog_BCC.txt`
2. **若存在**：已是索引目录，直接使用
3. **若不存在**：视为原始语料目录
   - 扫描目录下的语料文件（排除 Table 和 FSA 格式）
   - 检查 `dataPathIdx/` 是否存在且时间戳一致（避免重复索引）
   - 若需要索引，调用 `IndexBCC` 对所有语料文件建索引
   - 写入 `IdxLog_BCC.txt` 索引日志

### 5.3 语料查询

#### `CallBCC(query)`

执行原始 BCC 查询语句。

```python
result = bcc.CallBCC("学习{}Freq(100,$Q,0)")
result = bcc.CallBCC("学习{}Context(20,0,100)")
result = bcc.CallBCC("学习{}Count()")
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `query` | `str` | BCC 查询语句 |

**返回值**：`str`，JSON 格式查询结果。

**查询语句格式**：`查询词{}操作(参数)`
- `Freq(数量, 目标字段, 上下文条数)` — 词频统计
- `Context(窗口大小, 页码, 条数)` — 上下文检索
- `Count()` — 计数统计

#### `Run(Query, **Others)`

高级查询接口，通过关键字参数自动构造查询语句。

```python
# 词频查询（默认）
result = bcc.Run("学习")

# 指定查询模式
result = bcc.Run("学习", Command="Freq", Number=200)
result = bcc.Run("学习", Command="Context", WinSize=30, Number=100, PageNo=0)
result = bcc.Run("学习", Command="Count")

# 带逻辑运算
result = bcc.Run("学习 AND 方法", Command="Freq")
result = bcc.Run("学习 NOT 机器", Command="Freq")

# Lua 格式输出
result = bcc.Run("学习", Command="Freq", Print="Lua")
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `Query` | `str` | （必填） | 查询词或查询表达式 |
| `Command` / `Output` | `str` | `"Freq"` | 查询模式：`"Freq"` / `"Context"` / `"Count"` |
| `Number` | `int` | `100` | 返回条数上限 |
| `Target` | `str` | `"$Q"` | 目标字段标识符 |
| `WinSize` | `int` | `20` | 上下文窗口大小（`Context` 模式） |
| `PageNo` | `int` | `0` | 分页页码（`Context` 模式） |
| `Print` | `str` | `""` | 输出格式，`"Lua"` 为 Lua 脚本格式 |
| `Speedup` | `int` | `1` | 加速选项 |
| `ContextNum` | `int` | `0` | 上下文条数（`Freq` 模式附带上下文时使用） |

**返回值**：`str`，查询结果。

**查询语句自动生成规则**：
- 若 `Query` 不含 `{}`，自动追加 `{}`
- 若 `Query` 包含换行符，直接作为原始查询传入（不做拼接处理）
- `Freq` → `Query{}Freq(Number, Target, ContextNum)`
- `Context` → `Query{}Context(WinSize, PageNo, Number)`
- `Count` → `Query{}Count()`
- `AND` / `NOT` 运算符会在运算符前插入操作表达式

**示例**（Demo/BCC.py）：

```python
from LangSC import BCC

g = BCC("Corpus")
Ret = g.Run("喜欢{}", Command="Context", PageNo=0, WinSize=30, Number=10)
print(Ret)
```

### 5.4 KV 操作

BCC 引擎维护一个全局键值存储，可在查询间传递上下文信息。

#### `AddBCCKV(Key, Val)`

添加键值对。

```python
bcc.AddBCCKV("Filter", "新闻")
bcc.AddBCCKV("Tags", "人名;地名;机构名")
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `Key` | `str` | 键名 |
| `Val` | `str` | 值（多值分隔符自动合并为分号分隔） |

**返回值**：`str`。

#### `GetBCCKV(Key="")` / `GetBCCKVs(Key="")`

获取键值。

```python
val = bcc.GetBCCKV("Filter")
all_kvs = bcc.GetBCCKV()
```

**返回值**：`str`。

#### `ClearBCCKV(Key="")`

清空键值存储。

```python
bcc.ClearBCCKV()
```

**返回值**：`str`。

### 5.5 语料索引

#### `IndexBCC(filelistname, **Others)`

索引语料文件，支持多种输入格式。

```python
# 1. 索引整个目录（递归扫描）
bcc.IndexBCC("/path/to/corpus_dir")

# 2. 索引文件列表文件（每行一个文件路径）
bcc.IndexBCC("/path/to/filelist.txt")

# 3. 索引单个文件
bcc.IndexBCC("/path/to/corpus.txt")

# 4. 索引 Python 列表
bcc.IndexBCC(["file1.txt", "file2.txt", "file3.txt"])

# 5. 指定索引结构
bcc.IndexBCC("/path/to/corpus", Structure="HZ")        # 按汉字（默认）
bcc.IndexBCC("/path/to/corpus", Structure="Segment")    # 按分词
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `filelistname` | `str` 或 `list` | 语料来源：目录路径、文件列表路径、单个文件路径或 Python 文件路径列表 |
| `Structure` | `str` | 索引结构：`"HZ"`（默认，按汉字）、`"Segment"`（按分词） |

**返回值**：`int`，操作状态码。

**处理流程**：
1. 若输入为目录：递归收集所有文件路径
2. 若输入为文件列表：直接读取
3. 若输入为 Python 列表：写入临时文件
4. 对每个文件检测是否为原始文本（非 Table/Doc 格式），若是则预处理为 Doc 格式
5. 检测文件编码，非 GBK 编码的文件自动转换
6. 调用底层 `BCC_IndexBCC` 构建索引

### 5.6 BCC 方法速查表

| 方法 | 说明 |
|------|------|
| `BCC(dataPath)` | 构造函数，自动索引+加载 |
| `Run(Query, **Others)` | 高级查询接口 |
| `CallBCC(query)` | 执行原始查询 |
| `AddBCCKV(Key, Val)` | 添加键值 |
| `GetBCCKV(Key)` / `GetBCCKVs(Key)` | 获取键值 |
| `ClearBCCKV()` | 清空键值 |
| `IndexBCC(filelistname, **Others)` | 索引语料 |

---

## 6. JSS 类 — JSON 结构检索

JSS（JSON Structure Search）提供对 JSON 格式数据的结构化检索能力，支持 SQL 风格查询语法和多表管理。

### 6.1 构造函数

```python
from LangSC import JSS

jss = JSS(dataPath, log_level=0, log_filename='')
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `dataPath` | `str` | （必填） | 数据目录路径 |
| `log_level` | `int` | `0` | 日志级别（0=关闭） |
| `log_filename` | `str` | `""` | 日志文件路径 |

**说明**
- 自动加载 `jsslib` 动态库
- 使用 10MB 缓冲区
- 支持同时管理多个表（通过 `self.handles` 字典）
- 析构函数 `__del__` 自动调用 `Terminate()` 释放资源并卸载 DLL

### 6.2 自动索引机制

构造函数调用 `_init_jss_data(dataPath)` 自动处理索引：

```
步骤 1: 检查 dataPath/IdxLog_JSS.txt
         ├── 存在 → 已是索引目录 → 加载全部子目录中的表 → 完成
         └── 不存在 → 步骤 2

步骤 2: 扫描 dataPath 中的 *.json / *.jsonl 文件
         ├── 无文件 → 完成
         └── 有文件 → 步骤 3

步骤 3: 检查 dataPathIdx/IdxLog_JSS.txt
         ├── 存在且时间戳一致 → 从 dataPathIdx 加载 → 完成
         └── 不一致或不存在 → 步骤 4

步骤 4: 执行索引
         ├── 创建 dataPathIdx/ 目录
         ├── 逐个处理 *.json / *.jsonl 文件（跳过 cfg_* 前缀）
         ├── 查找对应的 cfg_<name>.txt（不存在则自动生成）
         ├── 为每个文件创建索引到 dataPathIdx/<name>/
         ├── 记录到 IdxLog_JSS.txt
         └── 加载全部表 → 完成
```

### 6.3 数据目录结构

**原始数据目录**（以 `./json` 为例）：

```
./json/
├── pinyin.jsonl              # 数据文件（JSONL 格式）
├── cfg_pinyin.txt            # pinyin 的配置文件（可选，缺失时自动生成）
├── books.json                # 也支持 JSON 数组格式
└── (cfg_books.txt)           # 可选
```

**命名规则**
- 数据文件：`<name>.json` 或 `<name>.jsonl`
- 配置文件：`cfg_<name>.txt`
- 以 `cfg_` 开头的文件在扫描时会被跳过

**索引后自动生成的目录**：

```
./jsonIdx/
├── IdxLog_JSS.txt            # 索引日志
├── pinyin/                   # pinyin 表的索引文件
│   └── (索引数据...)
└── books/                    # books 表的索引文件
    └── (索引数据...)
```

### 6.4 cfg 配置文件

cfg 文件为 JSON 格式，定义表结构和索引策略。

**示例**（`cfg_pinyin.txt`）：

```json
{
    "table_name": "pinyin",
    "record_format": "jsonl",
    "content": {
        "PYId": "PYId",
        "PinYin": "PinYin",
        "PinYin_FuHao": "PinYin_FuHao",
        "DengJi": "DengJi",
        "DuYin[]": "DuYin[]",
        "ShiPin": "ShiPin",
        "TuPian": "TuPian",
        "Source": "Source"
    },
    "index": {
        "number": [],
        "kv": ["PinYin", "PinYin_FuHao"],
        "affix": [],
        "bm25": []
    }
}
```

**字段说明**

| 字段 | 类型 | 说明 |
|------|------|------|
| `table_name` | `string` | 表名，用于查询时的 `FROM` 子句 |
| `record_format` | `string` | 数据格式：`"jsonl"`（每行一条 JSON）或 `"json"`（JSON 数组） |
| `content` | `object` | 字段映射。数组类型字段需加 `[]` 后缀 |
| `index.number` | `array` | 数值索引字段，支持范围查询（`>`, `<`, `>=`, `<=`） |
| `index.kv` | `array` | 键值索引字段，支持精确匹配查询（`=`） |
| `index.affix` | `array` | 词缀索引字段，支持前后缀匹配 |
| `index.bm25` | `array` | 全文检索字段，支持 BM25 相关性排序 |

### 6.5 cfg 自动生成规则

当 cfg 文件缺失时，JSS 自动读取数据文件的首条记录推断 schema：

1. **读取首条记录**
   - `.jsonl`：读取第一行
   - `.json`：若为数组取第一个元素，若为对象直接使用

2. **生成 `content` 映射**
   - 普通字段：`"field": "field"`
   - 数组字段：`"field[]": "field[]"`

3. **生成 `index` 配置**
   - `number`：仅当字段名为 `"id"` 且值为数值类型时加入
   - `kv`：所有字符串类型字段
   - `affix`：留空
   - `bm25`：留空

4. **写入** `cfg_<name>.txt`（UTF-8 编码）

**示例**：假设 `books.jsonl` 首条记录为：

```json
{"id": 1, "title": "自然语言处理", "author": "张三", "price": 59.8, "tags": ["NLP", "AI"]}
```

自动生成的 `cfg_books.txt`：

```json
{
    "table_name": "books",
    "record_format": "jsonl",
    "content": {
        "id": "id",
        "title": "title",
        "author": "author",
        "price": "price",
        "tags[]": "tags[]"
    },
    "index": {
        "number": ["id"],
        "kv": ["title", "author"],
        "affix": [],
        "bm25": []
    }
}
```

> 注意：`price` 字段虽为数值但字段名不是 `"id"`，不会自动加入 `number` 索引。若需范围查询，应手动编写 cfg。

### 6.6 查询

#### `Run(sql_statement, table="")`

执行 SQL 风格的查询。

```python
# 单表时无需指定 table
results = jss.Run('SELECT * FROM pinyin WHERE PinYin ="da1"')

# 多表时通过 table 参数指定
results = jss.Run("SELECT * FROM audio WHERE tags = 'pop';", table="audio")
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `sql_statement` | `str` | （必填） | SQL 查询语句 |
| `table` | `str` | `""` | 指定查询的表名。为空时使用第一个已加载的表 |

**返回值**：`list`，查询结果列表。每个元素为一条记录（`dict`）。未初始化时返回 `[]`。

**SQL 语法**

| 子句 | 说明 | 示例 |
|------|------|------|
| `SELECT` | 指定返回字段（`*` 返回全部） | `SELECT id, ci, pinyin` |
| `TOP n` | 限制返回条数 | `SELECT TOP 10 *` |
| `FROM` | 指定表名 | `FROM pinyin` |
| `WHERE` | 过滤条件 | `WHERE PinYin = 'da1'` |
| `AND` | 条件与 | `WHERE pos = 'n' AND freq > 100` |
| `OR` | 条件或 | `WHERE pos = 'n' OR pos = 'v'` |

| 运算符 | 说明 | 适用索引类型 |
|--------|------|-------------|
| `=` | 等于 | `kv`, `number` |
| `>` | 大于 | `number` |
| `<` | 小于 | `number` |
| `>=` | 大于等于 | `number` |
| `<=` | 小于等于 | `number` |

**示例**（Demo/JSS.py）：

```python
from LangSC import JSS

g = JSS("json")
Ret = g.Run('SELECT * FROM pinyin WHERE PinYin ="da1"')
print(Ret)
```

### 6.7 资源释放

#### `Terminate()`

释放所有已加载表的句柄。

```python
jss.Terminate()
```

**说明**
- 逐一释放 `self.handles` 中的所有句柄
- 重置 `is_init` 为 `False`
- 析构函数 `__del__` 会自动调用，但建议显式调用以确保资源及时释放

### 6.8 JSS 方法速查表

| 方法 | 说明 |
|------|------|
| `JSS(dataPath, log_level, log_filename)` | 构造函数，自动索引+加载 |
| `Run(sql_statement, table)` | SQL 查询 |
| `Terminate()` | 释放资源 |

---

## 7. 完整示例

### 7.1 GPF 句法分析与可视化

```python
from LangSC import GPF
import json

gpf = GPF()
Txt = "中欧班列持续稳定开行，夯实了亚欧大陆互联互通的基础"
js = gpf.Parse(Txt, Structure="Tree")
gpf.ShowStructure(js, "Dep.png")
```

### 7.2 GPF 手动构建网格与关系

```python
from LangSC import GPF
import json

Line = """
{"Words": ["瑞士", "率先", "破门", "，", "沙其理", "梅开二度", "。"],
"Tags": ["ns", "d", "v", "w", "nr", "i", "w"],
"Relations": [{"U1": 2, "U2":0,"R":"A0","KV":"KV1"},
{"U1": 2, "U2":1,"R":"Mod","KV":"KV2"},
{"U1": 5, "U2":4,"R":"A0","KV":"KV3"}]}"""

S = json.loads(Line)
Txt = "".join(S["Words"])
gpf = GPF()
gpf.SetText(Txt)

# 逐词添加 Unit
ColNo = 0
Units = []
for i in range(len(S["Words"])):
    UnitNo = gpf.AddUnit(S["Words"][i], ColNo + len(S["Words"][i]) - 1)
    Units.append(UnitNo)
    gpf.AddUnitKV(UnitNo, "POS", S["Tags"][i])
    ColNo += len(S["Words"][i])

# 添加关系
for R in S["Relations"]:
    gpf.AddRelation(Units[R["U1"]], Units[R["U2"]], R["R"])

# 可视化
gpf.ShowRelation("r.png")
```

### 7.3 GPF 关系操作

```python
from LangSC import GPF

gpf = GPF()
Text = "孩子们都吃撑了"
gpf.SetText(Text)
Child = gpf.AddUnit("孩子们", 2)
All = gpf.AddUnit("都", 3)
Eat = gpf.AddUnit("吃", 4)
Full = gpf.AddUnit("撑了", 6)

gpf.AddUnitKV(Eat, "POS", "V")
gpf.AddUnitKV(Full, "POS", "V")

gpf.AddRelation(Eat, All, "mod")
gpf.AddRelation(Eat, Full, "mod")
gpf.AddRelation(Eat, Child, "sbj")
gpf.AddRelation(Full, Child, "sbj")
gpf.AddRelationKV(Full, Child, "sbj", "K1", "V1")
gpf.AddRelationKV(Full, Child, "sbj", "K2", "V2")

# 遍历所有关系
R = gpf.GetRelation()
for r in R:
    print(r)
    print(gpf.GetUnitKV(r[0], "Word"), gpf.GetUnitKV(r[1], "Word"), r[2])
    KVs = gpf.GetRelationKV(r[0], r[1], r[2])
    for K, Vs in KVs.items():
        print(K)
```

### 7.4 GPF 序列结构与网格

```python
from LangSC import GPF

gpf = GPF()
Text = "我们大家很辛苦"
gpf.SetText(Text)

# 添加两层分词结构
gpf.AddStructure('["我们","大家","很","辛苦"]')
gpf.AddStructure('["我们","大家","很辛苦"]')

# 显示网格
gpf.ShowGrid()

# 遍历网格
Grid = gpf.GetGrid()
for Col in Grid:
    for Unit in Col:
        print(Unit, gpf.GetUnitKV(Unit, "Word"))
```

### 7.5 BCC 语料库查询

```python
from LangSC import BCC

bcc = BCC("Corpus")

# 上下文检索
ret = bcc.Run("喜欢{}", Command="Context", PageNo=0, WinSize=30, Number=10)
print(ret)

# 词频查询
freq = bcc.Run("学习", Command="Freq", Number=50)
print(freq)

# 计数
count = bcc.Run("学习", Command="Count")
print(count)

# 复合查询
result = bcc.Run("学习 AND 方法", Command="Freq", Number=20)
print(result)
```

### 7.6 BCC 语料索引

```python
from LangSC import BCC

bcc = BCC("./corpus_idx")

# 索引整个目录
bcc.IndexBCC("./raw_corpus/")

# 索引文件列表
bcc.IndexBCC("./filelist.txt")

# 索引 Python 列表
bcc.IndexBCC(["./doc1.txt", "./doc2.txt"])

# 以分词模式索引
bcc.IndexBCC("./raw_corpus/", Structure="Segment")
```

### 7.7 JSS 数据检索

```python
from LangSC import JSS

# 自动索引 + 加载
jss = JSS("json")

# 精确查询
results = jss.Run('SELECT * FROM pinyin WHERE PinYin ="da1"')
for row in results:
    print(row)

# 多条件查询
results = jss.Run("SELECT * FROM pinyin WHERE PinYin = 'da1' AND DengJi = '1';")

# 限制数量
results = jss.Run("SELECT TOP 5 * FROM pinyin;")

# 清理
jss.Terminate()
```

### 7.8 JSS 手动编写 cfg

```python
import json

cfg = {
    "table_name": "products",
    "record_format": "jsonl",
    "content": {
        "id": "id",
        "name": "name",
        "category": "category",
        "price": "price",
        "description": "description",
        "tags[]": "tags[]"
    },
    "index": {
        "number": ["id", "price"],
        "kv": ["name", "category"],
        "affix": ["name"],
        "bm25": ["description"]
    }
}

with open("./table/cfg_products.txt", "w", encoding="utf-8") as f:
    json.dump(cfg, f, indent=4, ensure_ascii=False)

from LangSC import JSS
jss = JSS("./table")
results = jss.Run("SELECT * FROM products WHERE price < 100;", table="products")
```

---

## 8. 数据文件格式说明

### 8.1 GPF Table 文件格式

Table 文件是纯文本格式，以 `Table <表名>` 开头，每行一个条目及其属性：

```
Table CiDian
天气
  POS n
  拼音 tianqi
北京
  POS ns
  类型 地名
```

### 8.2 GPF FSA 文件格式

FSA 文件以 `FSA <规则名>` 开头，定义状态转换规则：

```
FSA PersonRecognize
State Start
  Transition ...
```

### 8.3 BCC 语料文件格式

BCC 支持两种格式：

**Doc 格式**（结构化）：

```
Doc 文档名
#Global 字段=值
#Group pos=text
Item:这 是 第 一 句
Item:这 是 第 二 句
```

- `Doc` 行声明文档名
- `#Global` 行定义全局属性
- `#Group` 行定义分组属性
- `Item:` 行为具体语料条目，词之间用空格分隔

**原始文本格式**：纯文本，`IndexBCC` 会自动预处理为 Doc 格式（按句号分句，每个字用空格分隔）。

### 8.4 JSS 数据文件格式

**JSONL 格式**（`*.jsonl`）：每行一条 JSON 记录

```
{"id": 1, "ci": "爱", "pos": "v", "pinyin": "ai4"}
{"id": 2, "ci": "被", "pos": "p", "pinyin": "bei4"}
```

**JSON 格式**（`*.json`）：JSON 数组

```json
[
    {"id": 1, "ci": "爱", "pos": "v", "pinyin": "ai4"},
    {"id": 2, "ci": "被", "pos": "p", "pinyin": "bei4"}
]
```

---

## 9. 平台与依赖

### 9.1 动态库

| 平台 | GPF 库 | BCC 库 | JSS 库 |
|------|--------|--------|--------|
| Windows | `gpflib.dll` | `bcclib.dll` | `jsslib.dll` |
| Linux | `libgpflib.so` | `libbcclib.so` | `libjsslib.so` |
| macOS | `libgpflib.dylib` | `libbcclib.dylib` | `libjsslib.dylib` |

### 9.2 包内数据文件

| 文件 | 所属类 | 用途 |
|------|--------|------|
| `GPFconfig.txt` | GPF | GPF 引擎配置（Table/FSA 路径、远程服务地址） |
| `Segment.dat` | GPF | CRF 分词模型 |
| `idxPOS.dat` | GPF | 词性标注数据 |
| `BCCconfig.txt` | BCC | BCC 引擎配置（线程、内存、索引参数） |
| `Parser.lua` | BCC | Lua 查询解析脚本 |
| `base.lex` | JSS | 分词词典（affix/bm25 索引用） |
| `Graph/dot.exe` | GPF | Graphviz DOT 工具（Windows 可视化） |

### 9.3 线程安全

GPF 和 BCC 的初始化操作使用 `threading.Lock()` 保护，确保多线程环境下不会重复初始化：

| 全局变量 | 所属类 | 说明 |
|----------|--------|------|
| `IsCRFInit` | GPF | CRF 分词模型初始化标志 |
| `IsPOSInit` | GPF | POS 词性标注数据初始化标志 |
| `IsGPFInit` | GPF | GPF 数据初始化标志 |
| `IsBCCInit` | BCC | BCC 引擎初始化标志 |

### 9.4 索引日志文件

每个类使用独立的索引日志文件：

| 日志文件 | 所属类 | 存放位置 |
|----------|--------|----------|
| `IdxLog_GPF.txt` | GPF | `dataPath` 或 `dataPathIdx/` |
| `IdxLog_BCC.txt` | BCC | `dataPath` 或 `dataPathIdx/` |
| `IdxLog_JSS.txt` | JSS | `dataPath` 或 `dataPathIdx/` |

日志格式为 TSV（制表符分隔）：
```
文件名\t时间戳1\t时间戳2
```

---

## 10. 参考文献

说明文档及使用示例：http://gpf.blcu.edu.cn

> 荀恩东. 自然语言结构计算——GPF结构分析框架 [M]. 北京: 人民邮电出版社. 2022
