
简介ArcGIS DataReviewer 10.2 面向 GIS 数据生产、入库质检与空间数据维护人员聚焦空间位置、属性取值和拓扑关系中的常见错误排查可用于项目数据交付前的质量核查与问题定位也适合需要了解 ArcGIS 质检流程的初中级用户参考。压缩包共 157 个文件约 76.22MB包含 png、gif、jpg 等界面图标素材js、css、htm 构成的前端交互与帮助页面以及 xml 配置、exe/msi/cab 安装组件和 db、ini、txt 等数据说明文件整体兼顾工具安装与配套文档查阅。已有 1231 人学习下载具备一定的使用参考基础。读者可借助其中的质检功能资料了解空间规则、属性校验、拓扑检查、批处理任务、脚本接口和协作报告的落地方式也能结合安装组件与说明文件完成环境搭建为后续自定义质检规则、排查数据问题提供较完整的参考。1. 一份能拿去交付的质检链比一堆检查工具更值钱做过入库的人大概都有过这种时刻图层交上去对方随手一放大两个面叠在一起、一段线悬空三十厘米、某个必填字段是空的。返工本身不算最难受难受的是上一批数据犯过同样的错这一批又犯一遍。ArcGIS 的 Data Reviewer 解决的就是这件事——它把“靠眼睛看”变成一组能保存、能重跑、能统计的检查规则结果落在独立的质检库里谁在什么时候判了哪条错误都留痕。文件名里的 102 对应 10.2 这一代桌面端界面不新但规则引擎和结果表结构很扎实。这份资源适合正做入库质检、成果自检、跨部门交验的 GIS 从业者尤其是被“同一个错误反复出现”折磨过的那批人。2. 质检工程先立骨架Reviewer Workspace 与会话怎么建很多人第一次打开 Data Reviewer会下意识去找“检查”按钮结果发现得先有地方存结果。这个先后顺序弄反后面每一步都会别扭。这一章先把容器、环境、参数三件事捋顺再谈规则。2.1 结果为什么不写进源数据Workspace 的隔离设计Data Reviewer 的核心设计是“被检数据只读”。所有检查命中的问题不是打标记到源图层上而是写进一个独立的 Reviewer Workspace——本质是一个地理数据库里面有一张结果表常见名字是revReviewerTable和配套的会话记录表。这套隔离带来三个直接好处源数据不会被质检过程污染同一份数据可以反复检、检多轮而互不覆盖结果表可以当普通表去做统计、导出、发给不做 GIS 的同事看。非隔离的做法我也见过有人直接在源图层加个“错误标记”字段跑完检查自动写值。项目小的时候确实快但数据一交出去字段跟着走接收方打开一看多出一列莫名其妙的标记解释成本比省下的时间高得多。更麻烦的是多轮检查第二轮把第一轮的标记覆盖了出了问题谁也说不清是哪一轮判的。会话Session是第二层隔离。一次质检任务对应一个会话会话里记录操作人、时间、描述。同一个 Workspace 里放几十个会话是常态——按批次、按图幅、按人分开。后面做统计的时候用会话 ID 一过滤就不会出现“三轮结果加一起错误翻三倍”的尴尬。Workspace 的载体选型上单机作业我一般用 File GDB.gdb。Personal GDB.mdb在 10.2 时代还有 2GB 上限质检结果表增长很快跑几次大图层就顶到天花板属于典型的后悔药都买不到企业级 SDE 适合多人并发写、需要权限控制的场景但配置成本高一个人干活没必要上。2.2 从装完到工具条亮起来四个确认动作环境这块的坑集中在“以为装好了”。下面四个动作按顺序走一遍基本能把问题挡在前面。检查项在哪看不正常的表现桌面端主版本与资源包一致帮助 → 关于版本对不上扩展加载直接失败扩展已勾选自定义 → 扩展 → Data Reviewer工具条能调出来但按钮全灰工具箱可见ArcToolbox → Data Reviewer Tools找不到工具集脚本没法调Workspace 可写目标盘符的权限检查跑完提示成功结果表空第一项最容易被忽略。桌面端 10.2 是 32 位进程装在 64 位系统上跑没问题但同一台机器上如果同时存在别的版本注册表里指向哪个版本很容易搞混。判断方法很土但有效打开 ArcMap看标题栏和关于窗口里的版本号和你手上这个包对不对得上对不上就别装了先解决版本共存。第二项里有个细节扩展的勾选是跟着当前应用会话走的关掉 ArcMap 再打开需要重新勾。所以脚本化或批量作业的时候别指望上次勾过就一直有效。工具条本身在“自定义 → 工具条”里调出来调出来之后如果按钮还是灰的通常不是扩展没勾而是当前地图文档没保存到本地路径或者还没有连上任何一个会话。2.3 建 Workspace 和会话时那几个必填参数建库本身没什么难度难在每个参数填什么。用工具箱里的创建工具参数大致是这些参数填法建议填错的后果Workspace 位置本地固定盘符不要网络映射盘写到一半断连结果表损坏Workspace 类型File GDB用 Personal GDB 撞 2GB会话名称日期_批次_作业人如20240512_B03_lisi后期统计分不清批次用户名称真实作业人标识追责和复核时找不到人描述数据范围、规则版本号半年后自己都看不懂会话名称的命名规则值得单独说一句。我见过用“新建会话1、新建会话2”的跑到第七轮的时候没人知道哪个会话对应哪批数据只能挨个打开看血泪经验。带上日期和批次号成本是多敲十几个字符收益是半年后还能一眼认出来。提示会话名称里不要用空格和中文标点导出报告、写进文件名、拼命令行路径的时候会省掉一堆转义麻烦。2.4 用脚本把建库和建会话固定下来界面操作每批次重复一遍很烦尤其是一天跑十几个图幅的时候。把建库这一步脚本化后面批处理作业就能整条串起来。桌面端 10.2 自带 Python 2.7脚本直接在里面跑。# -*- coding: utf-8 -*- import arcpy, os, datetime base rD:\qc # 质检根目录尽量本地盘 batch B03 # 批次号按实际情况改 today datetime.date.today().strftime(%Y%m%d) gdb_name reviewer_%s_%s.gdb % (today, batch) gdb os.path.join(base, gdb_name) # 1) 建 Reviewer Workspace本质就是一个 File GDB if not arcpy.Exists(gdb): arcpy.CreateFileGDB_management(base, gdb_name, CURRENT) print(workspace:, gdb) # 2) 确认扩展许可返回值是 Available / Unavailable / CheckedOut print(DataReviewer:, arcpy.CheckExtension(DataReviewer))这段只做两件事建库、探许可。逻辑很直白——先保证容器存在再保证工具能用。参数上注意base用原始字符串r...否则 Windows 路径里的\会被当转义符batch换成你自己的批次标识别用中文。建会话的工具在工具箱里Python 里的函数名各版本不完全一致。稳妥做法是在 ArcToolbox 里右键那个工具 → Copy As Python Snippet把生成的调用粘进脚本参数顺序就不会错。我一般会把这个 snippet 单独存成create_session.py批处理脚本import它避免每次手敲。# -*- coding: utf-8 -*- # 下面这段的调用形式以你机器上 Copy As Python Snippet 的结果为准 import arcpy gdb rD:\qc\reviewer_20240512_B03.gdb session_name 20240512_B03_lisi # 典型参数顺序workspace、session 名称、user、description arcpy.CreateReviewerSession_Reviewer( gdb, session_name, lisi, 1:2000 更新入库 第三批 ) print(session created:, session_name)参数说明第一个是 Workspace 路径第二是会话名按 2.3 的命名规则来第三是作业人第四是描述。工具名带_Reviewer后缀是这类扩展工具的常见形式但不同小版本可能有出入所以上面特别标注了以实际 snippet 为准。这不是偷懒是这类老扩展的真实情况——照抄网上博客的函数名翻车概率相当高。库和会话都建好骨架就算立住了。接下来才是真正决定质检效果的部分规则怎么选、参数怎么填。3. 规则怎么落几何、属性、要素间检查的参数写法规则配错比不配更糟。不配至少知道自己没检配错了会生成一份“全部通过”的报告把问题盖住。这一章按检查类别拆开讲参数重点放在最容易出错的容差、子句和严重级别上。3.1 四类检查的分工先定拦什么再定怎么查Data Reviewer 的检查项按对象关系大致分四类实际项目里我一般照这个顺序铺类别典型规则参数要点常见误报来源几何自检空几何、自相交、重复折点、短线段长度/面积阈值阈值按显示单位而非地图单位填属性检查必填为空、域值越界、编码不在字典表SQL 子句、字段类型子句过滤掉全部要素要素间检查面重叠、面缝隙、线未连通、点不在面内容差、目标图层容差单位与坐标系不匹配完整性检查点线面必须有对应关系、外键必须存在关联字段、允许为空关联字段有空值但未排除顺序上有讲究先跑几何自检几何有问题的时候要素间检查会产生大量连带误报。举个具体场景一个面要素自相交它和相邻面的重叠检查会同时报错你以为是拓扑问题其实是几何本身坏了。先清几何再跑关系误报量能降一大截。属性检查放在几何之后、要素间之前比较合适。原因是属性不合规的要素往往本来就不该参与空间关系判断——比如状态字段标记为“已废弃”的要素还拿它去和现状数据做重叠检查纯属自找麻烦。3.2 容差和坐标系单位错了整批结果就是玄学这是全套参数里最容易翻车的一项没有之一。容差Tolerance用的是地图单位也就是数据框或要素类的坐标系单位。数据是投影坐标系米容差填 0.05 就是 5 厘米数据是地理坐标系度容差填 0.05 就是 0.05 度在赤道附近约 5.5 公里。同样一个数字含义差五个数量级。我见过最典型的一次一批 1:2000 的更新数据坐标系是地理坐标检查员按“米”的思路把面重叠容差设成 0.2跑出来几万条重叠人工抽查发现全是正常相邻面。查了两个小时才反应过来是单位问题。从那以后我这边有个硬规矩跑要素间检查之前先把数据投影到项目对应的投影坐标系容差一律按米填绝不留模糊空间。经验量级参考投影坐标系单位米成图比例尺几何容差要素间容差说明1:5000.050.050.10精细测图容差不能放大1:20000.200.200.50更新入库最常见的档位1:100001.001.002.00允许一定概化1:500005.005.0010.00只做粗筛不能当验收依据这些数字是经验值不是标准具体项目按技术设计书来。但有个判断原则可以通用容差应该小于“人眼在这个比例尺上能分辨的最小距离”大于这个值就是自欺欺人。还有一个常被忽略的点面积阈值。Web Mercator 这类投影在高纬度面积变形严重拿它算面积阈值判断“小面”结果会随纬度漂移。质检用的工作坐标系尽量选项目所在地的投影带。3.3 属性的规则写法子句、域和字典表属性检查分两档。第一档是结构性检查必填字段为空、值域越界、类型不符这类用要素类自身的域Domain配合检查项就能覆盖不需要写子句。第二档是业务性检查比如“编码必须在字典表里存在”“竣工日期不能早于开工日期”这类得靠 SQL 子句或者关联表。子句写法上有几个坑。字段名不要加引号包起来——File GDB 里STATE 01和STATE 01在不同工具里表现不一样稳妥写法是直接在属性选择里验证一遍能选出记录再往检查项里粘。日期字段要用数据库认的格式2024-05-12一般没问题2024/5/12就悬了。-- 必填为空只对状态为现状的要素做检查 STATE 01 AND (CODE IS NULL OR CODE ) -- 编码不在字典表用子查询字典表与检查图层同库 CODE NOT IN (SELECT CODE FROM DICT_DOMAIN WHERE DOMAIN_NAME LANDUSE) -- 日期逻辑竣工早于开工 END_DATE IS NOT NULL AND START_DATE IS NOT NULL AND END_DATE START_DATE第一段是空值判断注意IS NULL和 要同时写空字符串和 NULL 在 File GDB 里是两回事只判一个会漏。第二段是字典表校验前提是字典表和被检图层在同一个库或者能建立关联跨库子查询在老版本里支持有限。第三段是逻辑校验先把 NULL 排除掉否则NULL 某日期的结果是未知不会命中看起来像检查失效。注意子句写完先在地图里用“按属性选择”跑一遍看选中数量。数量为 0 就别往下走了先改子句数量等于全表说明条件写反了。3.4 严重级别与检查标题让结果表可排序每个检查项都能设严重级别一般 1 到 5。这个字段看起来是装饰实际决定了后面怎么用结果。我这边约定1 级是阻断项几何为空、必填字段为空这种不修完不许入库2 级是重要项面重叠、编码越界必须处理但要人工判断怎么处理3 级是提示项短线段、重复折点这类能修则修4、5 级基本只做记录用于统计趋势。约定好之后写进项目文档所有作业人按同一套来否则同一类错误在不同批次里级别不一样统计出来的趋势图没有意义。检查标题Check Title同样要规范。默认标题往往是“面重叠检查”这种跑三个图层就有三条同名记录结果表里根本分不清。建议加上图层前缀JC_DLTB_面重叠_1to2000。标题长度别超过 60 个字符导出 CSV 的时候部分工具会截断。规则配好一批之后逐条手动运行效率很低。下一步是把规则固化成批处理作业让它能一键跑完。4. 批处理作业与结果表让质检从点一次变成跑一遍规则再多靠点按钮跑也不现实。这一章讲三件事作业文件怎么组织、执行有哪几条路径、结果表怎么读。4.1 从单条检查到作业文件拆分的粒度批处理作业Batch Job把多条检查打包成一个文件通常是.rbj后缀。这个文件可以进版本库可以发给同事可以按项目归档是整套流程里最有复用价值的东西。拆分粒度上有个取舍。全塞进一个文件跑起来省事但出问题难定位——跑到第 40 条卡死你不知道是哪条规则的问题按单条检查拆成几十个文件定位容易但管理成本高。我一般按“图层 检查类别”拆比如地块图层的几何类一个、属性类一个、要素间一个一个中等项目下来十几个文件好管也好排查。命名上跟会话名对齐JC_DLTB_geo_v3.rbj。v3是规则版本号规则改了要升版本别在原文件上直接改。这个习惯来自一次教训——同一批数据跑了两轮用了不同版本的规则文件结果对不上查了半天才发现中间改过容差。作业文件里每个检查项要填的东西和单条检查一样目标图层、子句、容差、严重级别、检查标题。填完之后建议先只勾一条跑通了再全开。4.2 执行的三个入口界面、工具、命令行执行路径有三条按场景选。界面执行最直观工具条上的批处理按钮选.rbj、选会话点运行进度条走完就能看结果。适合规则调试阶段因为出错时提示比较友好。GP 工具执行适合串流程。工具箱里有一个执行批处理作业的工具输入是作业文件、会话、工作空间输出就是结果写进表。它可以在 ModelBuilder 里和其他工具串起来比如先做投影转换、再做拓扑检查、最后执行质检一条链跑完。命令行执行适合挂定时任务。桌面端自带的 Python 环境可以直接跑脚本脚本里调 GP 工具。夜间跑大图幅第二天早上看结果是我比较常用的节奏。# -*- coding: utf-8 -*- import arcpy, os gdb rD:\qc\reviewer_20240512_B03.gdb session 20240512_B03_lisi rbj rD:\qc\rules\JC_DLTB_geo_v3.rbj # 执行批处理作业参数顺序以 ArcToolbox 的 Copy As Python Snippet 为准 arcpy.ExecuteBatchJob_Reviewer(gdb, session, rbj, ALL) print(done:, os.path.basename(rbj))参数含义工作空间是结果落库的地方会话决定这批结果归到哪个批次作业文件是规则集合最后一个参数控制是全部执行还是只跑勾选项。同样提醒一句函数名以本机 snippet 为准各小版本存在差异。这条路径有一个隐性依赖脚本运行时扩展许可必须可用。定时任务用的是系统账户许可可能不可见。稳妥做法是在脚本开头显式检出跑完归还失败时把许可状态打出来。# -*- coding: utf-8 -*- import arcpy status arcpy.CheckOutExtension(DataReviewer) print(checkout:, status) # Available / AlreadyCheckedOut / Failed if status not in (Available, AlreadyCheckedOut): raise SystemExit(许可不可用先确认扩展勾选与授权) try: # 这里放实际的批处理调用 pass finally: arcpy.CheckInExtension(DataReviewer) # 用完归还避免占着不放逻辑说明先检出检出失败直接退出并打印原因别让它跑到一半才报错try/finally保证异常时也会归还许可否则下一次任务会因为“许可被占用”莫名其妙失败。这类问题在定时任务里特别隐蔽属于典型的黑匣子故障。4.3 读结果表先探字段再写统计结果表的结构在不同版本之间有差异字段大小写、命名都可能不一样。上来就写死字段名的脚本换台机器就崩。我的做法是先探再取。# -*- coding: utf-8 -*- import arcpy, os gdb rD:\qc\reviewer_20240512_B03.gdb table os.path.join(gdb, revReviewerTable) if not arcpy.Exists(table): raise SystemExit(结果表不存在检查 workspace 是否建对) # 第一步把字段全部打出来确认实际命名 for f in arcpy.ListFields(table): print(%-24s %-12s %s % (f.name, f.type, f.length))跑一遍屏幕上会列出所有字段。常见的包括检查标题、严重级别、审核状态、作业人、审核日期、要素标识这几类但确切名字以打印结果为准。这一步花三十秒能省掉后面半小时的 KeyError。拿到字段名之后写统计脚本用“按候选名匹配”的方式兼容不同命名# -*- coding: utf-8 -*- import arcpy, os, collections gdb rD:\qc\reviewer_20240512_B03.gdb table os.path.join(gdb, revReviewerTable) fields [f.name for f in arcpy.ListFields(table)] def pick(*cands): 按候选名匹配字段兼容不同版本命名差异 for c in cands: for f in fields: if f.lower() c.lower(): return f return None f_title pick(CHECKTITLE, ORIGINCHECKTITLE) f_sev pick(SEVERITY) f_status pick(REVIEWSTATUS) print(matched:, f_title, f_sev, f_status) # 按 检查标题 严重级别 统计命中数 counter collections.Counter() with arcpy.da.SearchCursor(table, [f_title, f_sev]) as cur: for title, sev in cur: counter[(title, sev)] 1 for (title, sev), n in counter.most_common(20): print(%-40s sev%s count%d % (title, sev, n))这段代码的逻辑是先用pick把字段名对上再用游标一次遍历做计数最后按数量倒序打印前 20 条。参数上没有花哨东西关键是pick这个兼容层——同一份脚本在 10.2 和更高版本上都能跑靠的就是它。审核状态字段的取值建议先跑一次界面在结果表里看看真实存的是什么不同版本可能存数字也可能存文本。别看文档看数据。这是我在这种老工具上总结出来的最省时间的一条。4.4 多批次结果的隔离与归档结果表是一个只增不减的东西一年下来几百万条记录很常见。不管的话打开结果表卡、统计慢、报告还容易算重复。做法是按会话隔离再定期归档。每轮质检一个新会话统计时用会话字段过滤。归档用工具箱里的结果导出工具把某个会话的结果导成独立表或文件然后从主表里清掉。清之前一定先导出并备份这个操作没有撤销。合并也有需求。多个作业人分头检不同图幅最后要出一份总报告用结果合并工具按会话合并到一张表。合并前确认各人的检查标题命名规则一致否则合并后同类错误会被拆成好几组统计图看着像两回事。到这儿流程基本能跑通了。但真跑起来问题才刚开始。5. 避坑与排查五个让质检白跑的真实现象下面五条都是实际跑出来的问题按“现象 → 原因 → 解决”写。看过一遍至少能省掉半天。5.1 环境与工程类工具条亮着但点不动现象扩展勾了工具条也调出来了按钮全是灰的鼠标放上去没有任何提示。原因多数情况不是安装问题而是当前没有可用的会话。工具条上的检查按钮依赖“当前活动会话”没有会话时按钮会禁用。其次是地图文档没有保存到本地路径文档在未命名状态下部分按钮同样不可用。解决先把 mxd 存到本地固定路径再从工具条打开会话管理器选一个已有会话或者新建一个按钮会立刻恢复。如果新建会话时报工作空间不可写检查目标目录权限网络映射盘是重灾区能换本地盘就换。5.2 规则与参数类跑完显示成功结果一条没有现象批处理作业提示执行完成打开结果表空空如也。原因三个高频点。一是子句把要素全过滤了字段名写错或者值的大小写不对条件永远为假二是检查范围被设成了“当前视图”而执行时视图缩放到了空白区域三是目标图层选成了空图层或者子类型不对。解决把子句清空先跑一次看有没有结果。有结果说明是子句问题回去用按属性选择验证没结果就检查范围设置改成“全部范围”再跑还没有就确认图层要素数GetCount一下别对着一个空图层调半小时参数。5.3 规则与参数类重叠检查报了几千条人工看都是正常的现象面重叠检查结果爆量抽查发现全是正常相邻面。原因容差单位错。数据是地理坐标系容差按米填实际被解释成度0.05 度在项目所在地大约等于几公里相邻面当然全“重叠”。解决把数据投影到项目对应的投影坐标系再检查容差按米重新设。临时应急也可以按纬度换算但那只是权宜之计长久了容易忘下次换个人接手又踩一遍。5.4 结果管理类跑三轮报告里的错误数变成三倍现象同一份数据连跑三轮导出的报告里错误数量翻倍增长。原因三轮都写进了同一个会话结果表累加。另一种可能是归档脚本没跑旧结果还在表里。解决一轮一个新会话会话名带批次号统计脚本里加会话过滤条件定期导出并清理历史结果。清理前必须备份这一步没有撤销。5.5 性能类跑到一半无响应只能强杀进程现象批处理跑到中途界面卡死等十分钟没反应只能任务管理器结束。原因桌面端是 32 位进程内存上限大约 2GB一次把所有图层所有规则塞进一个作业文件内存很快顶满。另外被检图层没有建空间索引要素间检查会退化成全表扫描。解决按图层拆作业文件分批跑给参与要素间检查的图层建空间索引大图幅按分幅拆分或者放到夜间跑。这三条做完同样的数据量通常能顺利跑完。6. 用结果表做门禁把质检报告变成一个能判定的动作质检报告给人看门禁给流程看。两者的区别在于报告可以是“有 37 条严重错误”门禁必须是“不通过退回”。后者才是真正能挡住问题数据的机制。做法不复杂读结果表按严重级别和审核状态算一个判定输出成 JSON 或者直接返回退出码交给入库脚本去判断。# -*- coding: utf-8 -*- import arcpy, os, json, sys gdb rD:\qc\reviewer_20240512_B03.gdb session 20240512_B03_lisi table os.path.join(gdb, revReviewerTable) fields [f.name for f in arcpy.ListFields(table)] def pick(*cands): for c in cands: for f in fields: if f.lower() c.lower(): return f return None f_sess pick(SESSIONID, REVIEWSESSIONID) f_sev pick(SEVERITY) f_stat pick(REVIEWSTATUS) blocking, pending 0, 0 with arcpy.da.SearchCursor(table, [f_sess, f_sev, f_stat]) as cur: for sid, sev, stat in cur: if str(sid) ! str(session): continue # 只看本轮会话 if sev is not None and int(sev) 2: blocking 1 # 1-2 级视为阻断项 if stat is None or str(stat) in (0, , None): pending 1 # 未审核的也算未通过 result {session: session, blocking: blocking, pending: pending, pass: blocking 0 and pending 0} print(json.dumps(result, ensure_asciiFalse)) sys.exit(0 if result[pass] else 1) # 退出码给上游脚本判断逻辑分三层按会话过滤保证只统计本轮按严重级别累加阻断项把未审核的记录也算进未通过——这一条容易被忽略结果表里躺着一堆没人判的记录直接放行等于默认它们都对。参数上sev 2这个阈值和 3.4 的约定要对齐改了约定记得同步改脚本。退出码是给上游用的0 通过、1 不通过入库脚本拿到 1 就回滚。判定结果建议按下面这张表落到流程里别只写数字判定条件动作通过阻断项 0未审核 0直接入库有条件通过阻断项 0未审核 0人工签核后入库退回阻断项 0退回作业人修完重跑这套门禁跑了两年多最大的体会是质检的价值不在于查出多少错而在于让“错误没修完就不能往下走”变成流程里的一条硬规则。以前靠人盯盯的人一忙就放过去了现在退出码是 1上游脚本直接停谁也不担责任。从那以后我每接一个新项目第一件事就是把结果表字段探一遍、把门禁脚本跑通再谈规则配置。希望帮到你。本文还有配套的精品资源点击获取