【问题标题】:Parsing SPARQL results to obtain hostname解析 SPARQL 结果以获取主机名
【发布时间】:2016-10-21 15:49:01
【问题描述】:

我有很多这样的三元组:

?s ex:url ?url

?url 可以是:

www.ex.com/data/1.html
www.ex.com/data/2.html
www.google.com/search
...

是否有可能使用 SPARQL 查询以某种方式过滤查询并获得不同的域列表?在示例中,www.ex.comwww.google.com

类似这样的:

SELECT distinct ?url
WHERE { ?s ex:url ?url }

但对待每个 url 绑定。当然,我可以全部获取它们,并在我的程序中逐个处理每个 url,但我认为 sparql 查询会更节省内存。我正在使用 Stardog - 以防它具有一些自定义功能。

【问题讨论】:

  • 您可以将 URL 的域绑定到一个新变量,然后选择这个变量。请参阅 SPARQL 规范以了解字符串操作和 REGEX。在第一次出现 / 之前,类似子字符串的东西应该可以工作。
  • 您能否详细说明如何将 URL 的域绑定到新变量?我知道 REGEX 操作,但它们似乎通过 FILTER 丢弃结果

标签: sparql stardog


【解决方案1】:

您可以使用不需要正则表达式的字符串操作来执行类似的操作。例如,您可以在“//”之后和“/”之前获取 URL 的字符串形式部分:

select ?url ?hostname {
  values ?url { <http://example.org/index.html> }
  bind(strbefore(strafter(str(?url),"//"),"/") as ?hostname)
}
---------------------------------------------------
| url                             | hostname      |
===================================================
| <http://example.org/index.html> | "example.org" |
---------------------------------------------------

这不使用正则表达式,并且可能比使用 regex 函数的解决方案更快。

但是,这可能仍然让您获得比主机名更多的信息,例如,如果 URL 类似于 http://username:password@example.org:8080,您将获得 username:password@example.org:8080,这不仅仅是主机名。

要更仔细地执行此操作,您需要选择 URI/URL 等规范之一,例如 RFC 3986,并查看语法组件部分。该语法的一些相关产生是:

URI         = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

      hier-part   = "//" authority path-abempty
                  / path-absolute
                  / path-rootless
                  / path-empty

权限组件前面有一个双斜杠(“//”),并且是 以下一个斜杠 ("/")、问号 ("?") 或数字结尾 符号(“#”)字符,或在 URI 的末尾。

authority   = [ userinfo "@" ] host [ ":" port ]

我不会处理所有这些(也许使用正则表达式来处理复杂的情况会更有意义),但最简单的方法是从 SPARQL 结果中获取 URI,然后使用实际的用于获取主机名的 URI 解析库。这是最可靠的解决方案,因为 URI 可能非常复杂。

【讨论】:

  • STRBEFORE+STRAFTER 如果 URL 不完整(缺少方案)不起作用,如问题中的示例所示。尽管在实际数据中显然并非如此。
  • 我同意你的最后一段。使用 URI 解析库听起来是最可靠的编程方式。我也会检查您的解决方案并随时测量,以查看 3 个选项中哪一个表现更好。谢谢
【解决方案2】:

REPLACEREGEX 一起使用:

BIND(REPLACE(STR(?url), "^(.*?)/.*", "$1") AS ?domain)

Example in Yasgui

编辑:正如@JoshuaTailor 在 cmets 中指出的那样,如果 ?url 中没有方案,STRBEFORE 会更好:

BIND(STRBEFORE(?url, "/") AS ?domain)

如果您需要担心 URL 方案(这会丢弃方案):

BIND(REPLACE(STR(?url), "^(https?://)?(.*?)/.*", "$2") AS ?domain)

当然,以上仅适用于基本的 http(s) URL,如果需要处理任意 URL,正则表达式会变得更加复杂。

这是一个处理任何或缺少的方案、端口号、身份验证信息和缺少的尾部斜杠的方法:

BIND(REPLACE(?url, "^(?:.*?://)?(?:.*?@)?([^:]+?)(:\\d+)?((/.*)|$)", "$1") AS ?domain)

请注意,使用正则表达式的查询可能会很慢。

【讨论】:

  • 您的第二个正则表达式效果很好!谢谢!第一个只返回 http:// 所以我怀疑它需要进一步调整我的情况,但第二个很好。我会做一个性能测试,因为正如你所说,它可能非常昂贵
  • 这里不需要正则表达式。您可以只使用 STRBEFORE 并获取/ 之前的字符串。而第二个 REGEX 不适用于非 HTTP(S) URL,例如ftp 等。这也会导致包含身份验证信息和端口信息的 URL 出现问题(例如,http://user:password@example.org:8080/index.html,您将获取user:password@example.org:8080
  • 顺便说一句,第一个也应该适用于我的问题 - 我的错误,我忘记了真实数据具有架构(http://...)
猜你喜欢
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 2021-03-08
  • 1970-01-01
相关资源
最近更新 更多