update
This commit is contained in:
@@ -298,3 +298,13 @@ kinit -r 参数后面指定的时间
|
||||
- baseDN 登录用户组
|
||||
- project用户组可以登录hive
|
||||
- **ou=project**,dc=yldev,dc=net
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 获取特权keytab
|
||||
|
||||
创建 hdfs@A.COM
|
||||
获取密钥 然后认证 即可使用特权hdfs账号 操作 hdfs 文件系统
|
||||
|
52
cdh/合并keytab.md
Normal file
52
cdh/合并keytab.md
Normal file
@@ -0,0 +1,52 @@
|
||||
### 操作步骤:
|
||||
|
||||
1. **准备工作**:确保所有需要合并的 keytab 文件(如 `user1.keytab`、`service.keytab` 等)都在当前目录,且系统已安装 Kerberos 客户端工具(含 `ktutil`)。
|
||||
|
||||
2. **启动 `ktutil` 交互式工具**:
|
||||
|
||||
```bash
|
||||
ktutil
|
||||
```
|
||||
|
||||
3. **加载需要合并的 keytab 文件**:
|
||||
依次输入以下命令,将每个 keytab 文件加载到内存中(替换文件名为实际文件):
|
||||
|
||||
```bash
|
||||
ktutil: read_kt user1.keytab # 加载第一个 keytab
|
||||
ktutil: read_kt service.keytab # 加载第二个 keytab
|
||||
ktutil: read_kt app.keytab # 加载更多 keytab(如有)
|
||||
```
|
||||
|
||||
4. **验证加载的密钥条目**:
|
||||
输入 `list` 命令查看已加载的所有主体和密钥信息,确认是否正确:
|
||||
|
||||
```bash
|
||||
ktutil: list
|
||||
```
|
||||
|
||||
5. **将所有条目写入新的合并 keytab 文件**:
|
||||
输入以下命令,将内存中的所有密钥写入一个新文件(如 `merged.keytab`):
|
||||
|
||||
```bash
|
||||
ktutil: write_kt merged.keytab
|
||||
```
|
||||
|
||||
6. **退出工具**:
|
||||
|
||||
```bash
|
||||
ktutil: quit
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 验证合并结果:
|
||||
|
||||
使用 `klist` 命令检查合并后的 keytab 是否包含所有主体:
|
||||
|
||||
```bash
|
||||
klist -k merged.keytab
|
||||
```
|
||||
|
||||
如果输出包含所有原始 keytab 中的主体,则合并成功。
|
192
java/先序遍历原理.md
Normal file
192
java/先序遍历原理.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# 先序遍历原理:从树结构到实际应用的深度解析
|
||||
先序遍历(Pre-order Traversal)是树结构中最基础、最常用的遍历方式之一,其核心思想是“先访问根节点,再递归遍历左子树,最后递归遍历右子树”。在部门树形结构等场景中,先序遍历的衍生设计(如左值右值标记法)能极大提升数据操作效率。以下从基础概念到实际应用展开详细解说。
|
||||
|
||||
|
||||
## 一、先序遍历的基础定义与核心规则
|
||||
### 1. 树结构的基本概念
|
||||
在讲解先序遍历前,需明确树的核心术语:
|
||||
- **节点**:树中的每个元素(如部门树形结构中的“部门”)。
|
||||
- **根节点**:树的顶层节点(无父节点,如公司总部)。
|
||||
- **子节点**:被父节点直接包含的节点(如“技术部”是“研发中心”的子节点)。
|
||||
- **叶子节点**:无任何子节点的节点(如“前端开发组”)。
|
||||
- **路径**:从根节点到某一节点的所有节点组成的序列。
|
||||
|
||||
### 2. 先序遍历的核心逻辑
|
||||
先序遍历的遍历顺序可概括为 **“根 → 左 → 右”**,即:
|
||||
1. 首先访问当前节点(记录或处理节点信息);
|
||||
2. 递归地对当前节点的**左子树**执行先序遍历;
|
||||
3. 递归地对当前节点的**右子树**执行先序遍历。
|
||||
|
||||
#### 示例:二叉树的先序遍历
|
||||
对如下二叉树(A为根节点,B、C为子节点):
|
||||
```
|
||||
A
|
||||
/ \
|
||||
B C
|
||||
/ \
|
||||
D E
|
||||
```
|
||||
先序遍历顺序为:
|
||||
**A → B → D → E → C**
|
||||
- 访问根节点A → 遍历左子树B → 访问B → 遍历B的左子树D → 访问D(无左右子树)→ 遍历B的右子树E → 访问E → 左子树遍历完成 → 遍历根节点A的右子树C → 访问C。
|
||||
|
||||
|
||||
## 二、多叉树的先序遍历(部门树场景适配)
|
||||
部门树等实际场景中,树通常是**多叉树**(一个父节点可包含多个子节点),先序遍历规则调整为:
|
||||
**“根 → 子树1 → 子树2 → ... → 子树n”**,即访问根节点后,按顺序递归遍历每个子树。
|
||||
|
||||
### 1. 多叉树先序遍历示例
|
||||
以某公司部门树为例(根节点为“总公司”,下设“技术部”“市场部”,技术部下设“前端组”“后端组”):
|
||||
```
|
||||
总公司(根节点)
|
||||
/ \
|
||||
技术部 市场部
|
||||
/ \
|
||||
前端组 后端组
|
||||
```
|
||||
先序遍历顺序为:
|
||||
**总公司 → 技术部 → 前端组 → 后端组 → 市场部**
|
||||
- 访问总公司 → 遍历第一个子树“技术部” → 访问技术部 → 遍历技术部第一个子树“前端组” → 访问前端组(无子节点)→ 遍历技术部第二个子树“后端组” → 访问后端组 → 技术部子树遍历完成 → 遍历总公司第二个子树“市场部” → 访问市场部。
|
||||
|
||||
|
||||
## 三、先序遍历在部门树存储中的核心应用:左值(lft)与右值(rgt)标记
|
||||
在部门树形结构存储优化中,先序遍历的核心价值在于通过**“进入标记”和“离开标记”** 记录节点的层级关系,即左值(lft)和右值(rgt)的设计。
|
||||
|
||||
### 1. 标记规则
|
||||
遍历过程中,每个节点会被标记两个值:
|
||||
- **左值(lft)**:首次访问节点(进入节点)时记录的序号(从1开始递增);
|
||||
- **右值(rgt)**:遍历完该节点的**所有子节点**后(离开节点)记录的序号。
|
||||
|
||||
### 2. 标记示例(基于上述部门树)
|
||||
| 遍历步骤 | 操作 | 节点 | lft值 | rgt值 |
|
||||
|----------------|---------------|------------|-------|-------|
|
||||
| 1 | 进入根节点 | 总公司 | 1 | - |
|
||||
| 2 | 进入子节点 | 技术部 | 2 | - |
|
||||
| 3 | 进入子节点 | 前端组 | 3 | - |
|
||||
| 4 | 离开前端组(无子节点) | 前端组 | - | 4 |
|
||||
| 5 | 进入子节点 | 后端组 | 5 | - |
|
||||
| 6 | 离开后端组(无子节点) | 后端组 | - | 6 |
|
||||
| 7 | 离开技术部(所有子节点遍历完成) | 技术部 | - | 7 |
|
||||
| 8 | 进入子节点 | 市场部 | 8 | - |
|
||||
| 9 | 离开市场部(无子节点) | 市场部 | - | 9 |
|
||||
| 10 | 离开总公司(所有子节点遍历完成) | 总公司 | - | 10 |
|
||||
|
||||
最终标记结果:
|
||||
| 节点 | lft | rgt |
|
||||
|------------|-----|-----|
|
||||
| 总公司 | 1 | 10 |
|
||||
| 技术部 | 2 | 7 |
|
||||
| 前端组 | 3 | 4 |
|
||||
| 后端组 | 5 | 6 |
|
||||
| 市场部 | 8 | 9 |
|
||||
|
||||
### 3. 核心规律(标记的价值所在)
|
||||
通过先序遍历标记的lft和rgt,形成以下关键规律,支撑高效查询:
|
||||
- **父子关系**:父节点的lft < 所有子节点的lft,且父节点的rgt > 所有子节点的rgt(如总公司lft=1 < 技术部lft=2,rgt=10 > 技术部rgt=7)。
|
||||
- **子孙范围**:一个节点的所有子孙节点,其lft和rgt均在该节点的lft和rgt之间(如技术部的子孙节点前端组、后端组,lft均在2-7之间)。
|
||||
- **叶子节点特征**:叶子节点无子孙,因此rgt = lft + 1(如前端组lft=3,rgt=4=3+1)。
|
||||
- **子孙数量计算**:某节点的子孙总数 = (rgt - lft - 1) / 2(如技术部子孙数=(7-2-1)/2=2,即前端组和后端组)。
|
||||
|
||||
|
||||
## 四、先序遍历的优缺点与适用场景
|
||||
### 1. 优势
|
||||
- **查询效率极高**:基于lft和rgt的规律,无需递归即可快速查询子孙节点、计算数量、判断叶子节点等,时间复杂度低。
|
||||
- **关系表达直观**:通过数值范围直接体现层级关系,避免传统parent_id的链式依赖。
|
||||
|
||||
### 2. 局限性
|
||||
- **维护成本高**:新增或删除节点时,需批量更新后续节点的lft和rgt(如插入一个节点需给所有lft大于插入位置的节点+2),数据量大时操作耗时。
|
||||
- **初始化复杂**:现有树形结构迁移时需全量遍历计算lft和rgt,层级过深或数据量大时成本高。
|
||||
|
||||
### 3. 适用场景
|
||||
最适合**查询频繁、结构稳定、数据量中等**的树形场景,如:
|
||||
- 企业组织架构(部门层级变动少,查询需求多);
|
||||
- 权限菜单树(菜单结构稳定,需频繁查询子菜单);
|
||||
- 分类目录树(如电商商品分类,查询远多于增删)。
|
||||
|
||||
|
||||
## 五、总结
|
||||
先序遍历作为树结构的基础遍历方式,其核心是“先根后子”的访问顺序。在部门树等场景中,通过衍生的lft和rgt标记法,将树形关系转化为数值范围关系,实现了查询效率的质的提升。理解先序遍历的原理,不仅能掌握这一优化方案的核心逻辑,更能深入理解树形数据结构在计算机存储与操作中的设计思想。实际应用中需结合业务的查询与写入频率、数据量大小,权衡其优势与维护成本,避免盲目套用。
|
||||
|
||||
|
||||
|
||||
## 六、附
|
||||
|
||||
查出所有子孙部门
|
||||
|
||||
```sql
|
||||
SET @lft := 9;
|
||||
SET @rgt := 18;
|
||||
SELECT * FROM department WHERE lft BETWEEN @lft AND @rgt ORDER BY lft ASC;
|
||||
/*例子中用BETWEEN将被查部门本身也查了出来。实际中可以用大于小于*/
|
||||
```
|
||||
|
||||
查询子孙部门总数
|
||||
|
||||
```
|
||||
总数 = (右值 - 左值 - 1) / 2
|
||||
```
|
||||
|
||||
新增部门
|
||||
|
||||
```sql
|
||||
SET @lft := 7;/*新部门的左值*/
|
||||
SET @rgt := 8;/*新部门的左值*/
|
||||
SET @level := 5;/*新部门的层级*/
|
||||
begin;
|
||||
/*将插入的后续边缘的节点左右数+2*/
|
||||
UPDATE department SET lft=lft+2 WHERE lft > @lft;
|
||||
UPDATE department SET rgt=rgt+2 WHERE rgt >= @lft;
|
||||
/*插入数据*/
|
||||
INSERT INTO department(name,lft,rgt,level) VALUES('新部门',@lft,@rgt,level);
|
||||
/*新增影响行数为0时,必须回滚*/
|
||||
commit;
|
||||
/*rollback;*/
|
||||
```
|
||||
|
||||
删除
|
||||
|
||||
```sql
|
||||
SET @lft := 7;/*要删除的节点左值*/
|
||||
SET @rgt := 8;/*要删除的节点右值*/
|
||||
begin;
|
||||
UPDATE department SET lft=lft-2 WHERE lft > @lft;
|
||||
UPDATE department SET rgt=rgt-2 WHERE rgt > @lft;
|
||||
|
||||
/*删除节点*/
|
||||
DELETE FROM department WHERE lft=@lft AND rgt=@rgt;
|
||||
/*删除影响行数为0时,必须回滚*/
|
||||
commit;
|
||||
```
|
||||
|
||||
直接子节点
|
||||
|
||||
```sql
|
||||
SET @level := 2;/*总经理的level*/
|
||||
SET @lft := 2;/*总经理的左值*/
|
||||
SET @rgt := 19;/*总经理的右值*/
|
||||
|
||||
SELECT * FROM department WHERE lft > @lft AND rgt < @rgt AND level = @level+1;
|
||||
```
|
||||
|
||||
祖宗链路
|
||||
|
||||
```sql
|
||||
SET @lft := 3;/*产品部左值*/
|
||||
SET @rgt := 8;/*产品部右值*/
|
||||
|
||||
SELECT * FROM department WHERE lft < @lft AND rgt > @rgt ORDER BY lft ASC;
|
||||
```
|
||||
|
||||
计算层级
|
||||
|
||||
```sql
|
||||
-- 统计祖链节点数量,再加1即为当前节点层级
|
||||
SELECT COUNT(*) + 1 AS level
|
||||
FROM department
|
||||
WHERE lft < 3 AND rgt > 4;
|
||||
```
|
||||
|
||||
```
|
||||
直接存储 层级
|
||||
```
|
||||
|
Reference in New Issue
Block a user