给产品参数库挂上 Dataset 标注:GEO 数据下载页进入 AI 引擎视野的规范解读
适用读者:装备制造、工业零部件、材料行业的官网/内容运营与前端同学。手上有一批选型参数表、能耗实测数据、工况手册要做成下载栏目,并且能改页面模板里的 JSON-LD。写这篇的人刚给自家 12 个数据集补完标注,中途踩过的坑都留在正文里。
下载页挂着 CSV,AI 引擎却当它不存在
我们官网「资料下载」栏目挂着 12 个文件:5 张选型参数表、4 份能耗实测数据、2 本工况手册、1 个查询接口。销售同事每天在电话里念这些数,客户也确实靠它做选型。

把这些页面的 HTML 抓下来看,head 里除了站点级 Organization 什么都没有。正文就是一句「离心泵选型参数表(2026 Q1)」加一个 <a href="/dl/pump.csv">下载</a>。对用户够用,对机器等于一句废话:抓取器拿到的是一个没有描述的二进制资源,不知道里面是参数、是价格、还是宣传册。
问 AI 引擎「谁有离心泵额定扬程的公开数据」,答案里出现的是开放数据平台、行业协会仓储、几家门户的整理文章,我们一次都没被提到。不是内容不行,是内容没有被描述过——这正是生成式引擎优化(Generative Engine Optimization, GEO)要解决的那类问题。
先弄清楚 AI 引擎怎么给数据源排座次
AI 引擎不是只做关键词匹配。它先在候选源池里挑一批可能靠谱的来源,再做一次可信度判断,最后才决定引用谁。这个"挑"的动作,高度依赖结构化的元数据。
页面里的一句人话描述,机器要猜;一段结构化数据(structured data),机器直接读。前者受表述风格影响,后者是固定字段,跨站点可比。GEO 的活儿,很大一部分就是把"我们有什么"翻译成机器能比对的字段。
原理剖析:结构化描述如何参与可信度评估
我们复盘下来,引擎判断一个数据源能不能引,主要压在三件事上:能不能归属、能不能下载、能不能复用,再加上一层"内容对不对得上提问"。
flowchart TD
A["用户提问:谁有离心泵选型参数的公开数据"] --> B["候选源池"]
B --> C["开放数据平台 Dataset 已标注"]
B --> D["行业门户文章 无数据集标注"]
B --> E["厂商下载页 无数据集标注"]
C --> F["可归属:creator 与 publisher"]
C --> G["可下载:distribution.contentUrl"]
C --> H["可复用:license"]
C --> I["可对上:variableMeasured"]
F --> J["进入引用候选"]
G --> J
H --> J
I --> J
D --> K["只被当作背景描述"]
E --> L["通常被整个跳过"]
四件事缺一件,权重就往下掉一档。可归属解决"这数据是谁发的",没有 creator/publisher,引擎只能把来源算成匿名文件;可下载解决"能不能真的拿到",distribution 里给的 contentUrl 必须是不带跳转、能直接请求的完整地址;可复用解决"我引用它合不合规",license 缺失时,偏保守的引擎会直接跳过,因为它没法替用户承担版权风险。
第四条最容易被忽略。variableMeasured 是把"数据集里到底有什么列"讲给机器听的字段,也是查询词和数据本体之间做语义对齐的桥。用户问"额定扬程",如果你的数据集只有一句 description 提到"参数齐全",匹配不上;如果 variableMeasured 里明明白白写着 额定扬程 / m / minValue-maxValue,就能对上。
结论很直白:AI 引擎偏好有结构描述的数据源,不是因为它"更喜欢 Schema.org",而是因为结构化描述把归属、获取、授权、内容四件事变成了可比对、可打分的量。
该填哪些字段:Dataset 字段规范对照
先说清楚对象。数据集(Dataset)是 schema.org 里专门描述"一批数据本身"的类型,数据下载(DataDownload)是它的分发方式,两者是包含关系,不是并列。很多人把下载页标成 WebPage 就收工,等于告诉引擎"这是个页面",而不是"这里有批数据"。
下面这张表是我们内部落地时用的对照表,分必填、建议、可选三档。
| 字段 | 类型/取值 | 我们的填法 | 常见错 |
|---|---|---|---|
@type |
Dataset | 固定写 Dataset,不写 WebPage | 页面类型和数据类型混用 |
name |
Text | 数据本体名,如「离心泵选型参数数据集(2026 Q1)」 | 写成「资料下载」栏目名 |
description |
Text | 一句话说清覆盖范围与记录数 | 写成营销口号的宣传语 |
creator / publisher |
Organization | 填法人主体,带 url | 只填部门名或品牌缩写 |
license |
URL | 可访问的许可协议地址 | 填中文短句「免费使用」 |
distribution |
DataDownload | 一个文件一个条目,多格式并列 | 多个文件塞进同一个字符串 |
variableMeasured |
PropertyValue | 列级别描述,带单位与范围 | 复制一份 description 上去 |
dateModified / version |
Date / Text | 数据一改就更新 | 建页时填一次再也不动 |
temporalCoverage / spatialCoverage |
Text | 实测数据的时段与地区 | 漏填导致时效判断失真 |
measurementTechnique |
Text | 实测方法或标准号 | 空着,靠正文补 |
isAccessibleForFree |
Boolean | 免费公开就写 true | 漏填,被当成收费资源 |
citation / sameAs |
Text / URL | 关联论文或站内主页 | 只在有对应物时填 |
byteSize 和 encodingFormat 挂在 distribution 上,不在 Dataset 顶层。encodingFormat 用 IANA 媒体类型,CSV 写 text/csv,PDF 写 application/pdf,别写 .csv 这种后缀。
variableMeasured 写多细,才不算白写
这是争议最大的一栏。我们的结论是:写到"列"这一级,不写到单元格。
| 粒度 | 写法示例 | 引擎能用上的程度 |
|---|---|---|
| 只有 name | 「离心泵选型参数」 | 仅能做主题匹配,答不上具体问题 |
| name + keywords | 关键词堆 8 个参数名 | 能做模糊匹配,无法给数值 |
| variableMeasured(纯名字) | PropertyValue.name = 额定扬程 |
能做字段对齐,无量程概念 |
| variableMeasured + 单位与范围 | name + unitText + minValue/maxValue |
能对齐查询词,还能判断覆盖区间 |
| 逐行记录全量导出 | 412 行全塞进 JSON-LD | 页面体积失控,抓取成本上升 |
我们最后定的是每个数据集写 6 到 12 个核心变量,只写用户真正会问的那几列。选型参数表写了额定流量、额定扬程、必需汽蚀余量、配套电机功率、效率、介质温度;能耗数据集写了工况点、比能耗、运行时长、环境温度。
给范围值时注意,minValue/maxValue 是 PropertyValue 的属性,unitText 写人类可读单位(m³/h),unitCode 可选用 UN/CEFACT 代码。单位写中文还是符号,我们统一写符号,因为查询词里出现的多半是符号。
license 这栏到底怎么选
制造业填这个有心理障碍:参数表是自家工程师一版版攒出来的,标成公开许可,等于把东西白送。
我们的处理办法是分层。真正公开、希望被行业引用的选型数据集,走知识共享署名 4.0(CC BY 4.0),页面底部保留署名要求;带客户工况信息的实测数据不放进公开下载,只给登录用户,Dataset 标注也就不做——没有公开分发的数据集不该标 isAccessibleForFree: true,标了反而会被判为误导。
几个边界:许可地址必须是能打开的 URL,不能写文字;站内的自定义使用条款也能当 license 用,但要保证那个页面稳定可访问,且能被抓取;CC0 意味着放弃署名要求,对想保留品牌露出的一方偏激进。
给 12 个数据集补标注的落地记录
3 月 12 日盘了一下午,把栏目里 12 个文件挨个打开,记下格式、行数、更新频率、能不能公开。4 月 3 日改完模板上线,一个数据集对应一个页面、一段 JSON-LD。
下面这段是选型参数表数据集的成品,注释行在线上版本里要删掉,浏览器不认带 // 的 JSON:
{
// @context 固定写 schema.org,缺了整段不生效
"@context": "https://schema.org/",
// 类型必须是 Dataset,写成 WebPage 就白标了
"@type": "Dataset",
// name 描述数据本体,不是栏目名
"name": "离心泵选型参数数据集(2026 Q1 版)",
// description 说清覆盖范围和记录数,别写宣传语
"description": "覆盖 0.75–315 kW 卧式离心泵的额定流量、扬程、必需汽蚀余量、效率与配套电机功率,共 412 条型号记录。",
// 版本号配合 dateModified 一起给,方便引擎区分新旧
"version": "2026Q1",
// 数据一改就更新,引擎靠它判时效
"dateModified": "2026-04-02",
// 语言用 BCP 47 标签,中文站写 zh-CN
"inLanguage": "zh-CN",
// 免费公开要显式写 true,省略容易被当成收费资源
"isAccessibleForFree": true,
// creator 与 publisher 都填法人主体,带上官网 url
"creator": {
"@type": "Organization",
"name": "某某装备制造有限公司",
"url": "https://example.com"
},
// publisher 与 creator 同主体时也别省,两栏查的不是一件事
"publisher": {
"@type": "Organization",
"name": "某某装备制造有限公司"
},
// license 必须是可访问 URL,中文短句不合规
"license": "https://creativecommons.org/licenses/by/4.0/",
// variableMeasured 写到列级别,带单位与量程
"variableMeasured": [
{
// 第一个变量:额定流量,单位写符号而非中文
"@type": "PropertyValue",
"name": "额定流量",
"unitText": "m³/h",
// minValue/maxValue 给覆盖区间,引擎靠它判断能否回答取值类提问
"minValue": 6.3,
"maxValue": 1450
},
{
// 第二个变量:额定扬程,用户查询词里出现频率最高的一列
"@type": "PropertyValue",
"name": "额定扬程",
"unitText": "m",
"minValue": 8,
"maxValue": 210
},
{
// 第三个变量:必需汽蚀余量,工程上常被问到
"@type": "PropertyValue",
"name": "必需汽蚀余量",
"unitText": "m",
"minValue": 1.8,
"maxValue": 9.5
}
],
// 每个格式一个 DataDownload 条目,数组不要压成字符串
"distribution": [
{
// 机器可读版本优先放第一个
"@type": "DataDownload",
// encodingFormat 用 IANA 媒体类型,不写文件后缀
"encodingFormat": "text/csv",
// contentUrl 必须是不带跳转、能匿名直接下载的完整地址
"contentUrl": "https://example.com/dl/pump-selection-2026Q1.csv",
// byteSize 给字符串形式的字节数
"byteSize": "184320",
"datePublished": "2026-04-02"
},
{
// 同一份数据的人类可读版本,并列成第二个条目
"@type": "DataDownload",
"encodingFormat": "application/pdf",
"contentUrl": "https://example.com/dl/pump-selection-2026Q1.pdf",
"byteSize": "2310000"
}
]
}
改完 12 个页面,光靠肉眼盯不住,写了个小脚本批量查必填字段:
# 环境:Python 3.10+,依赖 requests、beautifulsoup4
# 用途:批量校验下载页的 Dataset 必填字段,缺哪个直接列出来
import json
import re
import requests
from bs4 import BeautifulSoup
# 顶层这五项缺一项,引擎就不把它当完整数据集看
REQUIRED = ["name", "description", "license", "variableMeasured", "distribution"]
# distribution 内部三项缺一个,抓取器只会当成普通文件
SUB_REQUIRED = ["@type", "encodingFormat", "contentUrl"]
def check(url):
# 超时拉短一点,12 个页面排队时不至于卡死
html = requests.get(url, timeout=15).text
soup = BeautifulSoup(html, "html.parser")
problems = []
for tag in soup.find_all("script", attrs={"type": "application/ld+json"}):
# 先剥掉我们注释用的 // 行,否则 json.loads 直接抛异常
raw = re.sub(r"^\s*//.*$", "", tag.string or "", flags=re.M)
node = json.loads(raw)
# 页面里可能有多段 JSON-LD,只挑 Dataset 类型
graph = node.get("@graph", [node])
for item in graph:
# 站点级的 Organization 之类直接跳过
if item.get("@type") != "Dataset":
continue
# 把缺的字段名连同 URL 一起记下来,方便定位
for key in REQUIRED:
if key not in item:
problems.append(f"{url} 缺少 {key}")
# distribution 可能是单个对象,也可能是数组
dists = item.get("distribution", [])
if isinstance(dists, dict):
dists = [dists]
for dist in dists:
# 逐个分发条目检查,PDF 和 CSV 都要覆盖到
for key in SUB_REQUIRED:
if key not in dist:
problems.append(f"{url} distribution 缺少 {key}")
return problems
if __name__ == "__main__":
# 12 个下载页地址,跑一遍就能看出哪几个还没补齐
pages = [f"https://example.com/dl/{slug}" for slug in ["pump", "blower", "motor"]]
# 展平成一行行问题,直接贴给前端改
found = [p for page in pages for p in check(page)]
print("\n".join(found) if found else "全部数据集字段齐全")
脚本能查字段,查不了"这个链接到底能不能匿名拿到"。补一条 curl:
# 环境:Linux / macOS / Git Bash,依赖 curl
# 用途:确认 contentUrl 能被匿名直接下载,返回 200 且媒体类型正确
curl -sSI "https://example.com/dl/pump-selection-2026Q1.csv" \
| grep -iE "^(HTTP/|content-type|content-length)"
# 期望输出大致是这样:
# HTTP/2 200
# content-type: text/csv
# content-length: 184320
# 若返回 302 跳登录页,这个 contentUrl 就不能写进 distribution
脚本第一次跑,报出来 9 条问题:3 个页面的 contentUrl 写成了相对路径,2 个 PDF 的 encodingFormat 写成 .pdf,4 个老数据集的 dateModified 还停在 2023 年。修完再跑,干净了。
flowchart LR
subgraph 标注前
P1["下载页 HTML"] --> P2["a 标签指向 CSV"]
P2 --> P3["抓取器:未知二进制资源"]
P3 --> P4["AI 回答:不引用"]
end
subgraph 标注后
Q1["下载页 + Dataset JSON-LD"]
Q1 --> Q2["variableMeasured 对齐查询词"]
Q1 --> Q3["DataDownload 给出可下载链接"]
Q1 --> Q4["license 给出复用边界"]
Q2 --> Q5["AI 回答:引用下载页"]
Q3 --> Q5
Q4 --> Q5
end
标注之后,AI 回答里出现了什么
4 月下旬,我用几组提问反复试:把「离心泵 额定扬程 参数 数据集 下载」这类话丢给几个带联网能力的 AI 搜索。标注之前,答案里给的是行业门户的整理文章;标注之后,有两三个回答把我们的下载页列进了来源,还带上了"该数据集覆盖 412 条型号记录"这种明显来自 description 的表述。
这个观察样本很小,不能当成效果结论,只能说明一件事:描述写清楚了,引擎确实会把厂商站点当成参数数据的候选源之一,不再是自动跳过。
产品部的吴工给我转了段客户通话记录,原话是"你们官网那个表我下下来了,但我想确认 315 kW 那档的汽蚀余量是不是 9.5"。他把这当成好消息——客户开始把官网表当成可核对的公共资料,而不是随手要份报价单。
几个容易踩的坑,和一点趋势预判
误区一,把 Dataset 标注当成页面 SEO 的附属品,字段随手填。空的 variableMeasured 比不标更糟,等于告诉引擎"我有数据但说不清是什么"。
误区二,license 图省事填 https://example.com/license,而那个页面根本不存在。许可地址打不开,可复用这一档直接归零。
误区三,数据更新了只改 CSV 文件,忘了改 dateModified。时效性是引擎判断"这份数据还活着"的主要信号,一年没动的 dateModified 会让它显得像归档物。
往后看,AI 引擎对数据资产的引用粒度会从"页面"往"数据集实体"下沉。现在它引的是下载页,下一步很可能是直接引数据集里的某个变量、某个取值区间。能提前把参数表拆成"数据本体 + 元数据"两份维护的厂商,会占一点先手。
技术上的收尾建议只有一条:别把 JSON-LD 当一次性装修。把它接进发布流程,数据集更新时自动带上 version 与 dateModified,比事后人工补 12 个页面省力得多。你们在给参数库做标注时卡在哪个字段上,评论区聊聊。
参考与延伸
- Dataset 类型定义与全部属性:https://schema.org/Dataset
- DataDownload(分发方式)说明:https://schema.org/DataDownload
- variableMeasured 属性规范:https://schema.org/variableMeasured
- 数据集结构化数据的实现说明:https://developers.google.com/search/docs/appearance/structured-data/dataset
GEO, AI搜索, Schema.org, Dataset Schema, JSON-LD, 结构化数据, 开放数据, 设备厂商 AI 获客