简介:这份《2022FME转换器快速参考手册-中文版》面向使用FME Workbench进行空间数据转换与集成的GIS从业者、数据处理工程师及初学者,帮助读者快速查阅各类转换器的功能定位与适用场景,解决转换器数量庞大、英文文档查阅不便的问题。资源包共1个PDF文件,大小约2.04MB,内容按功能分类编排,涵盖3D转换器、计算器、收集器、坐标系、数据库、过滤器、几何操作符、KML、线性引用、列表、操作员、MRF、网络、点云、栅格、字符串、Styler、曲面、Web服务、工作流及XML等模块,并对属性按钮颜色状态、必填字段、默认参数等界面操作要点作了说明。手册以概要形式逐类介绍每个转换器的作用,如CSGBuilder构建实体几何、Extruder生成拉伸表面、AngularityCalculator计算倾斜度等,便于按需检索。目前已有1680人学习下载,适合作为日常开发中的速查工具书。
1. FME 转换器快速参考手册到底解决什么问题:从 200 多个 Transformer 里捞出你要的那一个
刚接手一个数据交付项目,甲方丢过来一堆 DWG、Shapefile、Excel 和 GeoJSON,要求统一转成带坐标系的 GDB,还要做字段映射和拓扑检查。打开 FME Workbench,左侧转换器列表拉不到底,光是读名字就花了半小时——这是很多人第一次用 FME 的真实状态。FME 转换器快速参考手册这类资料的价值,不在于教你 FME 是什么,而在于当你知道「我要做字段拼接」「我要做空间过滤」「我要做坐标系转换」的时候,能在一分钟内定位到对应的 Transformer,并且知道关键参数怎么填。它面向的是已经装好 FME Workbench、能拖控件连线、但面对几百个转换器不知道选哪个的从业者。核心矛盾只有一个:转换器太多,而实际项目里高频使用的可能不到三十个。把高频转换器吃透,比背完整本手册有用得多。
2. 高频转换器分类与选型逻辑:先搞清楚你缺的是哪一类能力
2.1 按数据流角色分四类,而不是按字母顺序背
FME 转换器的官方分类有几十种,但落到实际工作流里,你只需要按「数据流角色」来记。第一类是读取与格式转换,比如 Shapefile 读进来、DWG 读进来,这类通常由 Reader 完成,但FeatureReader可以在工作流中间动态读取其他数据集。第二类是几何处理,包括GeometryCoercer(几何类型强制转换)、Reprojector(坐标系重投影)、Clipper(裁剪)、Dissolver(融合)。第三类是属性处理,高频的有AttributeManager(字段增删改)、AttributeCreator(新建字段)、AttributeValueMapper(值映射)、StringConcatenator(字符串拼接)。第四类是过滤与分流,Tester、TestFilter、Sampler、DuplicateFilter都属于这一类。
为什么按角色分而不是按字母?因为你在搭建工作流时的思维顺序就是「先读进来、再改几何、再改属性、最后分流输出」。按这个顺序去记忆转换器,比从 A 到 Z 翻手册快得多。我一般会在 Workbench 里把常用转换器加进收藏夹,但收藏之前你得先知道它属于哪一类,否则收藏夹也会变成垃圾堆。
2.2 选型时最容易搞混的三组转换器
第一组:AttributeCreator和AttributeManager。前者只负责新建字段,后者可以新建、改名、删除、重排、改类型,功能更全但配置面板更复杂。如果你只是加一个计算字段,用AttributeCreator更快;如果你要做一批字段的批量重命名和类型调整,用AttributeManager一次搞定。
第二组:Tester和TestFilter。Tester输出两个端口——通过和失败,适合二值判断。TestFilter可以输出多个端口,适合多条件分流。很多人用多个Tester串联来做多条件,结果工作流里全是连线,后期维护很痛苦。条件超过两个的时候,直接上TestFilter。
第三组:Clipper和SpatialFilter。Clipper是用裁剪边界去切目标要素,输出的是被切过的几何。SpatialFilter是做空间关系判断(相交、包含、分离等),输出的是原始要素,只是按空间关系分流。如果你要的是「把落在行政区内的要素挑出来但保持原样」,用SpatialFilter;如果你要的是「把全国数据裁成某个省的范围」,用Clipper。
2.3 用 Workbench 搜索框快速定位转换器
在 FME Workbench 的转换器面板顶部有一个搜索框,直接输入关键词比翻分类树快。但搜索有技巧:输入功能词比输入转换器名更有效。比如你想做字符串拼接,搜 “concatenate” 能直接命中StringConcatenator;你想做去重,搜 “duplicate” 能命中DuplicateFilter。如果搜不到,试试同义词——比如 “merge” 可能对应FeatureMerger,”join” 可能对应FeatureJoiner。
# FME 命令行快速查询转换器帮助(需安装 FME Desktop) # 列出所有转换器名称,配合 grep 过滤关键词 fmehelp --list-transformers | grep -i "attribute" # 查看某个转换器的详细参数说明 fmehelp AttributeManager上面这段命令用的是 FME 自带的fmehelp工具,在 FME Desktop 安装目录的fme文件夹下可以找到。--list-transformers会输出全部转换器名称,配合grep做关键词过滤,比在 GUI 里翻快。fmehelp AttributeManager会打印该转换器的参数列表和说明,适合在写 Workbench 脚本或做批量配置时快速查阅。注意这个工具在不同 FME 版本里的输出格式可能有差异,但核心参数名是一致的。
3. 用 PythonCaller 把转换器能力扩展到脚本级:参数怎么传、异常怎么接
3.1 PythonCaller 的定位:不是替代转换器,而是补转换器做不到的事
FME 自带转换器覆盖了绝大多数常规操作,但总有一些场景让你觉得「就差一点」——比如要根据多个字段的复杂逻辑生成一个新字段,要调用外部 API 做地址解析,要对几何坐标做自定义数学变换。这时候PythonCaller就是出口。它的本质是在工作流中间插入一个 Python 脚本节点,每个要素进来执行一次你的函数,你可以读取和修改要素的几何与属性,然后输出到下一个转换器。
关键认知:PythonCaller不是让你重写整个工作流,而是让你在转换器链条的某个环节做一次「自定义加工」。能用内置转换器组合出来的逻辑,不要用 PythonCaller,因为脚本的维护成本比连线高。只有当内置转换器组合超过四五个节点还搞不定的时候,才考虑上脚本。
3.2 一个可复用的 PythonCaller 模板:字段拼接加条件赋值
import fme import fmeobjects def process_feature(feature): """ PythonCaller 入口函数,每个要素执行一次。 功能:读取多个字段,按条件拼接生成新字段,并处理空值。 """ # 读取原始字段,getAttribute 返回字符串或 None road_name = feature.getAttribute('ROAD_NAME') road_code = feature.getAttribute('ROAD_CODE') road_level = feature.getAttribute('ROAD_LEVEL') # 空值保护:FME 中空字段可能返回 None 或空字符串 road_name = road_name.strip() if road_name else '' road_code = road_code.strip() if road_code else '' # 条件拼接逻辑 if road_name and road_code: full_label = f"{road_code}-{road_name}" elif road_name: full_label = road_name elif road_code: full_label = road_code else: full_label = 'UNKNOWN' # 根据道路等级追加后缀 level_suffix = {'1': '(主干)', '2': '(次干)', '3': '(支路)'} full_label += level_suffix.get(str(road_level), '') # 写回要素属性 feature.setAttribute('FULL_LABEL', full_label) # 输出要素到下一个转换器 self.pyoutput(feature)这段代码的核心逻辑分四步:读取字段、空值保护、条件拼接、写回属性。feature.getAttribute()是 FME Python API 的标准读取方法,返回类型取决于字段类型,字符串字段返回str或None。空值保护那两行是血泪经验——FME 里空字段有时候是None,有时候是空字符串,不统一处理的话后面拼接会报TypeError。feature.setAttribute()写回时如果字段不存在会自动创建。最后self.pyoutput(feature)把要素推到下一个端口,漏写这行的话要素就丢了,工作流会静默少数据,排查起来很费时间。
3.3 PythonCaller 的参数传递与异常处理
PythonCaller支持在转换器配置面板里传入自定义参数,在脚本里通过self.getParameter()读取。比如你不想把道路等级的后缀硬编码在脚本里,可以定义一个参数LEVEL_SUFFIX_MAP,在面板里填 JSON 字符串,脚本里解析。
import json def process_feature(feature): # 从转换器参数中读取配置,参数名在面板中定义 suffix_json = self.getParameter('LEVEL_SUFFIX_MAP') try: suffix_map = json.loads(suffix_json) if suffix_json else {} except json.JSONDecodeError: suffix_map = {} # 参数解析失败时记录到 FME 日志,不中断流程 fmeobjects.FMELogFile().logMessage( "LEVEL_SUFFIX_MAP 参数不是合法 JSON,已使用空映射" ) road_level = str(feature.getAttribute('ROAD_LEVEL') or '') full_label = feature.getAttribute('FULL_LABEL') or '' full_label += suffix_map.get(road_level, '') feature.setAttribute('FULL_LABEL', full_label) self.pyoutput(feature)参数传递的关键点:self.getParameter()返回的永远是字符串,需要自己转类型。异常处理不要直接raise,因为一个要素报错会导致整个转换中断。用FMELogFile().logMessage()写日志,流程继续跑,事后看日志排查。这是我在生产环境里踩过坑之后固定下来的写法——宁可少处理一个要素,不要让整个任务挂掉。
4. SQL 与 FeatureJoiner:属性关联和查询下推的两种路径
4.1 什么时候用 SQL,什么时候用 FeatureJoiner
FME 里做表关联有两种主流方式:一种是用FeatureJoiner转换器,把两个数据流的要素按关键字段做 join;另一种是用SQLExecutor或FeatureReader直接对数据库执行 SQL 查询,把结果读进来。选哪个取决于数据源和性能要求。
如果两个数据流都已经在 Workbench 里了(比如一个是 Shapefile 读进来的,一个是 Excel 读进来的),用FeatureJoiner最直接,不需要外部数据库支持。如果数据在 PostgreSQL、SQL Server、Oracle 里,而且关联字段有索引,用SQLExecutor把 join 下推到数据库执行,性能会好很多——尤其是大表关联的时候,FeatureJoiner是在 FME 内存里做笛卡尔积再过滤,数据量大时内存吃不消。
4.2 SQLExecutor 的典型配置与参数说明
-- 在 SQLExecutor 中执行的查询,:feature_id 是 FME 传入的要素属性占位符 SELECT a.id, a.name, b.category, b.priority FROM main_table a LEFT JOIN category_table b ON a.category_code = b.code WHERE a.region = :region_code AND a.status = 'ACTIVE'这段 SQL 放在SQLExecutor转换器里执行,:region_code是 FME 的占位符语法,对应上游要素的region_code属性值。SQLExecutor会为每个进入的要素执行一次查询,把结果字段合并到要素上。关键参数:Reader选择数据库连接,SQL Statement填上面的查询,Attributes to Expose列出你要暴露的结果字段名(比如category、priority),不列的话结果字段不会出现在下游。
性能注意点:如果上游要素有几千个,每个都执行一次 SQL,总查询次数就是几千次。这时候要么在 SQL 里做批量处理(用IN子句),要么改用FeatureReader一次性把整表读进来再用FeatureJoiner关联。我一般会在SQLExecutor前面加一个Sampler做测试,确认 SQL 逻辑正确后再放开全量。
4.3 FeatureJoiner 的 Join Mode 怎么选
FeatureJoiner有三个 Join Mode:Inner(只输出匹配上的)、Left(保留左表全部,右表匹配不上填空)、Full(两边都保留)。默认是 Inner,但实际项目里 Left 用得最多——比如你有一批道路要素,要关联行政区名称,有些道路可能落在行政区边界外,用 Left 能保留这些道路,行政区名称字段为空,后续可以单独处理。用 Inner 的话这些道路直接丢了,数据量对不上,甲方会找你麻烦。
5. 避坑与排查:转换器用错、参数填错、性能翻车的五个真实场景
5.1 坐标系没设对,Reprojector 转了等于没转
现象:用Reprojector把数据从 CGCS2000 转到 WGS84,输出后坐标值几乎没变,或者偏移量完全不对。原因:FME 读取数据时如果没有正确识别源坐标系,Reprojector的源坐标系就是错的,转换结果自然不对。解决:在 Reader 里手动指定源坐标系,或者在Reprojector里把 Source Coordinate System 从 “Read from feature” 改成手动指定。检查方法是在 Workbench 里用CoordinateSystemSetter强制设定源坐标系,再接Reprojector。
5.2 AttributeManager 的字段顺序和类型被静默修改
现象:经过AttributeManager之后,某些字段的类型从整数变成了字符串,或者字段顺序变了导致下游FeatureJoiner关联失败。原因:AttributeManager的默认行为是保留所有输入字段,但如果你在配置面板里手动添加了同名字段并指定了不同类型,它会覆盖原始类型。解决:在AttributeManager里只操作你需要改的字段,不要全选;对于不需要动的字段,确保 Action 是 “Nothing” 而不是 “Auto”。
5.3 PythonCaller 里 self.pyoutput 漏写导致数据静默丢失
现象:工作流跑完了,日志显示读取了 1000 个要素,但输出只有 800 个,没有任何报错。原因:PythonCaller脚本里某些分支没有调用self.pyoutput(feature),这些要素就被丢弃了。解决:在脚本的每个逻辑分支末尾都确保有self.pyoutput,或者在函数开头先写一个默认输出,后面再根据条件覆盖。排查方法是在PythonCaller后面接一个Counter转换器,对比上下游要素数量。
5.4 FeatureJoiner 在大数据量下内存溢出
现象:Workbench 跑到FeatureJoiner节点时卡死,内存占用飙升,最终报 out of memory。原因:FeatureJoiner会把两个数据流全部加载到内存做 join,数据量超过几万条就容易出问题。解决:改用SQLExecutor把 join 下推到数据库;或者先用Tester过滤掉不需要关联的要素,减少数据量;或者用FeatureMerger替代,FeatureMerger是流式的,内存占用更低,但要求关联字段唯一。
5.5 SQLExecutor 的占位符没传进去导致全表扫描
现象:SQLExecutor执行很慢,日志里看到每次查询都是全表扫描。原因:占位符:region_code对应的上游字段名拼写错误,FME 传进去的是空值,SQL 变成WHERE region = '',数据库无法用索引。解决:在SQLExecutor前面加一个Logger转换器,打印要素的region_code值,确认字段名和值都正确。另外注意占位符的冒号前面不要有空格,:region_code和: region_code在 FME 里行为不同。
6. 用 WorkspaceRunner 做批量转换:把单次 Workbench 变成可调度的流水线
当你已经把单个 Workbench 调通,下一步往往是要对几十个文件跑同样的流程。手动一个个改 Reader 路径再点运行,效率太低。WorkspaceRunner转换器可以让你在一个主 Workbench 里调用另一个子 Workbench,并且把参数传进去。具体做法:子 Workbench 里把输入路径设为 Published Parameter,主 Workbench 用WorkspaceRunner指向子 Workbench 的.fmw文件,在参数映射里把文件路径列表传进去。
# 在 PythonCaller 中生成待处理文件列表,输出为要素属性 import os def process_feature(feature): # 假设输入要素携带了根目录路径 root_dir = feature.getAttribute('ROOT_DIR') if not root_dir or not os.path.isdir(root_dir): return # 目录不存在则跳过 # 遍历目录下所有 .dwg 文件 for fname in os.listdir(root_dir): if fname.lower().endswith('.dwg'): # 为每个文件创建一个新要素 new_feature = feature.clone() new_feature.setAttribute('SOURCE_FILE', os.path.join(root_dir, fname)) self.pyoutput(new_feature)这段脚本的作用是把一个目录下的所有 DWG 文件展开成多个要素,每个要素带一个SOURCE_FILE属性。下游接WorkspaceRunner,把SOURCE_FILE映射到子 Workbench 的输入路径参数上,就能实现批量转换。关键参数:WorkspaceRunner的 “Workspace” 填子 Workbench 的完整路径,”Parameters” 里做属性到参数的映射。注意子 Workbench 里对应的参数必须是 Published 的,否则WorkspaceRunner看不到。
验证批量转换是否成功,不要只看主 Workbench 的日志。我一般会在子 Workbench 的输出端加一个写日志的Logger,记录每个文件的输出要素数量,然后在主 Workbench 跑完后去日志目录里按文件名逐个核对。这个习惯帮我抓到过好几次「某个文件因为编码问题读进来是空」的情况——主流程不报错,但输出文件是空的,只有逐个核对才能发现。
最后一个习惯:每次调通一个 Workbench,把关键转换器的参数截图存一份,和.fmw文件放在同一个目录。过三个月再回来改,你不可能记得当时FeatureJoiner的 Join Mode 选的是哪个、PythonCaller里那个空值判断为什么要写两遍。这份截图比任何手册都管用。希望帮到你。
本文还有配套的精品资源,点击获取