如何在SPARQL中优雅生成时间序列绑定(替代VALUES)
在SPARQL中优雅生成日期序列(替代手动VALUES)
我需要编写SPARQL查询返回特定时间点的物品数量,目前用VALUES手动定义日期序列:
VALUES ?date { "1960-01-01"^^xsd:date "1970-01-01"^^xsd:date "1980-01-01"^^xsd:date "1990-01-01"^^xsd:date "2000-01-01"^^xsd:date "2010-01-01"^^xsd:date "2020-01-01"^^xsd:date }
最终通过GROUP BY ?date得到结果,但时间序列更长或分辨率更高时,手动定义太繁琐。有没有类似Python range()的优雅方法来创建?date的绑定?
1. 通用递归查询方案(兼容SPARQL 1.1)
SPARQL 1.1支持递归查询,不用依赖特定引擎就能生成连续日期序列。比如生成1960到2020年每10年的1月1日:
WITH RECURSIVE ?dateSeq AS ( SELECT "1960-01-01"^^xsd:date AS ?date WHERE {} UNION SELECT ?nextDate WHERE { ?dateSeq ?date . BIND(?date + "P10Y"^^xsd:duration AS ?nextDate) FILTER(?nextDate <= "2020-01-01"^^xsd:date) } ) SELECT ?date FROM ?dateSeq
要调整时间分辨率,直接修改xsd:duration参数即可:
- 每年生成:
P1Y - 每月生成:
P1M - 每日生成:
P1D
2. 特定引擎的扩展函数(更简洁)
不同RDF数据库自带了更便捷的日期生成函数,写法更高效:
Blazegraph
使用bd:generateDates直接生成指定范围的日期序列:
SELECT ?date WHERE { bd:generateDates("1960-01-01"^^xsd:date, "2020-01-01"^^xsd:date, "P10Y"^^xsd:duration) ?date }
Virtuoso
通过GENERATE_SERIES生成年份序列,再构造目标日期:
SELECT STRDT(CONCAT(STR(?year), "-01-01"), xsd:date) AS ?date WHERE { ?year GENERATE_SERIES(1960, 2020, 10) }
Stardog
利用stardog:generate-series生成连续日期:
SELECT ?date WHERE { ?date stardog:generate-series("1960-01-01"^^xsd:date, "2020-01-01"^^xsd:date, "P10Y"^^xsd:duration) }
3. 基于现有数据动态生成(依赖数据存在性)
如果你的数据集里已有对应时间的物品记录,可以提取年份后构造目标日期,不用硬编码时间范围:
SELECT DISTINCT STRDT(CONCAT(STR(?year), "-01-01"), xsd:date) AS ?date WHERE { ?item :hasDate ?itemDate . BIND(YEAR(?itemDate) AS ?year) FILTER(?year >= 1960 && ?year <= 2020 && ?year % 10 = 0) }
内容的提问来源于stack exchange,提问作者Belda
相关产品推荐
相关产品推荐

