【问题标题】:To use iSPARQL to compare values using similarity measures使用 iSPARQL 使用相似性度量比较值
【发布时间】:2014-07-03 14:53:05
【问题描述】:

我有一个问题要问你。

我想写一个查询,检索与给定字符串“Londn”相似的值(给定一个相似度函数,例如Lev),以与谓词“RDFS:label”进行比较数据库百科。例如,在输出中,我想获得“伦敦”的值。 我读过一个可用的方法可能是使用 iSPARQL(“Imprecise SPARQL”),尽管它在文献中的使用并不广泛。

我可以使用 iSPARQL 还是有一些 SPARQL 方法来执行相同的操作?

【问题讨论】:

    标签: sparql semantic-web similarity dbpedia linked-data


    【解决方案1】:

    短版 - 您可以在纯 SPARQL 中完成其中的一些操作

    您可以使用这样的查询来查找名称类似于“Londn”的城市,并按(一种度量)相似度对它们进行排序。答案的其余部分解释了这是如何工作的:

    select ?city ?percent where {
      ?city a dbpedia-owl:City ;
            rdfs:label ?label .
      filter langMatches( lang(?label), 'en' )
    
      bind( replace( concat( 'x', str(?label) ), "^x[^Londn]*([L]?)[^ondn]*([o]?)[^ndn]*([n]?)[^dn]*([d]?)[^n]*([n]?).*$", '$1$2$3$4$5' ) as ?match )
      bind( xsd:float(strlen(?match))/strlen(str(?label)) as ?percent )
    }
    order by desc(?percent)
    limit 100
    

    SPARQL results

    city                                  percent
    ----------------------------------------------
    http://dbpedia.org/resource/London    0.833333
    http://dbpedia.org/resource/Bonn      0.75
    http://dbpedia.org/resource/Loudi     0.6
    http://dbpedia.org/resource/Ladnu     0.6
    http://dbpedia.org/resource/Lonar     0.6
    http://dbpedia.org/resource/Longnan   0.571429
    http://dbpedia.org/resource/Longyan   0.571429
    http://dbpedia.org/resource/Luoding   0.571429
    http://dbpedia.org/resource/Lodhran   0.571429
    http://dbpedia.org/resource/Lom%C3%A9 0.5
    http://dbpedia.org/resource/Andong    0.5
    

    计算字符串相似度指标

    注意:此答案的这一部分中的代码适用于 Apache Jena。实际上有一个边缘情况导致 Virtuoso (正确地)失败。最后的更新解决了这个问题。

    SPARQL 中没有内置任何东西来计算字符串匹配距离,但您可以使用 SPARQL 中的正则表达式替换机制来完成其中的一些。假设您要匹配某些字符串中的序列“cat”。然后您可以使用这样的查询来确定序列“cat”中存在多少给定字符串:

    select ?string ?match where {
      values ?string { "cart" "concatenate" "hat" "pot" "hop" }
      bind( replace( ?string, "^[^cat]*([c]?)[^at]*([a]?)[^t]*([t]?).*$", "$1$2$3" ) as ?match )
    }
    
    -------------------------
    | string        | match |
    =========================
    | "cart"        | "cat" |
    | "concatenate" | "cat" |
    | "hat"         | "at"  |
    | "pot"         | "t"   |
    | "hop"         | ""    |
    -------------------------
    

    通过检查字符串的长度和匹配,您应该能够计算出一些不同的相似度指标。作为使用您提到的“Londn”输入的更复杂的示例。百分比列是与输入匹配的字符串的百分比。

    select ?input
           ?string
           (strlen(?match)/strlen(?string) as ?percent)
    where {
      values ?string { "London" "Londn" "London Fog" "Lando" "Land Ho!"
                       "concatenate" "catnap" "hat" "cat" "chat" "chart" "port" "part" }
    
      values (?input ?pattern ?replacement) {
        ("cat"   "^[^cat]*([c]?)[^at]*([a]?)[^t]*([t]?).*$"                              "$1$2$3")
        ("Londn" "^[^Londn]*([L]?)[^ondn]*([o]?)[^ndn]*([n]?)[^dn]*([d]?)[^n]*([n]?).*$" "$1$2$3$4$5")
      }
    
      bind( replace( ?string, ?pattern, ?replacement) as ?match )
    }
    order by ?pattern desc(?percent)
    
    --------------------------------------------------------
    | input   | string        | percent                    |
    ========================================================
    | "Londn" | "Londn"       | 1.0                        |
    | "Londn" | "London"      | 0.833333333333333333333333 |
    | "Londn" | "Lando"       | 0.6                        |
    | "Londn" | "London Fog"  | 0.5                        |
    | "Londn" | "Land Ho!"    | 0.375                      |
    | "Londn" | "concatenate" | 0.272727272727272727272727 |
    | "Londn" | "port"        | 0.25                       |
    | "Londn" | "catnap"      | 0.166666666666666666666666 |
    | "Londn" | "cat"         | 0.0                        |
    | "Londn" | "chart"       | 0.0                        |
    | "Londn" | "chat"        | 0.0                        |
    | "Londn" | "hat"         | 0.0                        |
    | "Londn" | "part"        | 0.0                        |
    | "cat"   | "cat"         | 1.0                        |
    | "cat"   | "chat"        | 0.75                       |
    | "cat"   | "hat"         | 0.666666666666666666666666 |
    | "cat"   | "chart"       | 0.6                        |
    | "cat"   | "part"        | 0.5                        |
    | "cat"   | "catnap"      | 0.5                        |
    | "cat"   | "concatenate" | 0.272727272727272727272727 |
    | "cat"   | "port"        | 0.25                       |
    | "cat"   | "Lando"       | 0.2                        |
    | "cat"   | "Land Ho!"    | 0.125                      |
    | "cat"   | "Londn"       | 0.0                        |
    | "cat"   | "London"      | 0.0                        |
    | "cat"   | "London Fog"  | 0.0                        |
    --------------------------------------------------------
    

    更新

    上面的代码在 Apache Jena 中有效,但在 Virtuoso 中失败,因为模式可以匹配空字符串。例如,如果您在 DBpedia 的端点(由 Virtuoso 提供支持)上尝试以下查询,您将收到以下错误:

    select (replace( "foo", ".*", "x" ) as ?bar) where {}
    

    Virtuoso 22023 错误基于正则表达式的 XPATH/XQuery/SPARQL replace() 函数无法搜索即使在 空字符串

    这让我感到惊讶,但 replace 的规范说它基于 XPath fn:replace。 fn:replace 的文档说:

    如果模式匹配零长度,则会引发错误 [err:FORX0003] 字符串,即如果表达式 fn:matches("", $pattern, $flags) 返回真。但是,如果捕获的子字符串是 零长度。

    不过,我们可以通过在模式和字符串的开头添加一个字符来解决这个问题:

    select ?input
           ?string
           (strlen(?match)/strlen(?string) as ?percent)
    where {
      values ?string { "London" "Londn" "London Fog" "Lando" "Land Ho!"
                       "concatenate" "catnap" "hat" "cat" "chat" "chart" "port" "part" }
    
      values (?input ?pattern ?replacement) {
        ("cat"   "^x[^cat]*([c]?)[^at]*([a]?)[^t]*([t]?).*$"                              "$1$2$3")
        ("Londn" "^x[^Londn]*([L]?)[^ondn]*([o]?)[^ndn]*([n]?)[^dn]*([d]?)[^n]*([n]?).*$" "$1$2$3$4$5")
      }
    
      bind( replace( concat('x',?string), ?pattern, ?replacement) as ?match )
    }
    order by ?pattern desc(?percent)
    
    --------------------------------------------------------
    | input   | string        | percent                    |
    ========================================================
    | "Londn" | "Londn"       | 1.0                        |
    | "Londn" | "London"      | 0.833333333333333333333333 |
    | "Londn" | "Lando"       | 0.6                        |
    | "Londn" | "London Fog"  | 0.5                        |
    | "Londn" | "Land Ho!"    | 0.375                      |
    | "Londn" | "concatenate" | 0.272727272727272727272727 |
    | "Londn" | "port"        | 0.25                       |
    | "Londn" | "catnap"      | 0.166666666666666666666666 |
    | "Londn" | "cat"         | 0.0                        |
    | "Londn" | "chart"       | 0.0                        |
    | "Londn" | "chat"        | 0.0                        |
    | "Londn" | "hat"         | 0.0                        |
    | "Londn" | "part"        | 0.0                        |
    | "cat"   | "cat"         | 1.0                        |
    | "cat"   | "chat"        | 0.75                       |
    | "cat"   | "hat"         | 0.666666666666666666666666 |
    | "cat"   | "chart"       | 0.6                        |
    | "cat"   | "part"        | 0.5                        |
    | "cat"   | "catnap"      | 0.5                        |
    | "cat"   | "concatenate" | 0.272727272727272727272727 |
    | "cat"   | "port"        | 0.25                       |
    | "cat"   | "Lando"       | 0.2                        |
    | "cat"   | "Land Ho!"    | 0.125                      |
    | "cat"   | "Londn"       | 0.0                        |
    | "cat"   | "London"      | 0.0                        |
    | "cat"   | "London Fog"  | 0.0                        |
    --------------------------------------------------------
    

    【讨论】:

    • 谢谢约书亚。你的回答很有吸引力。您提出的方法考虑到我事先知道字符串及其长度。如果我们假设我们在代码中在运行时“计算”了一个字符串,那么重用这个查询就变得复杂了,还是我错了?
    • 我要再写一个问题吗?
    • 如果您在运行时获得输入,那么以编程方式从中构造模式和替换字符串应该不会太难。根据您在代码中执行此操作的方式,将它们注入到您的查询中应该不会太难。
    • 嗨 Joshua,我正在阅读您的回答,我注意到如果我运行您的 SPARQL 查询(第一个),我不会在响应中得到伦敦。为什么?
    • @Musich87 查询仍然可以正常工作,但它要求的内容类型为 dbpedia-owl:City。如果您运行查询select ?type { dbpedia:London a ?type },您将看到dbpedia:London 显然不再具有dbpedia-owl:City 类型。我不知道为什么会这样,但这就是为什么它没有出现在查询结果中。这是使用实时数据集的一部分危险。数据可能会在我们不查看时发生变化。您可以将 dbpedia-owl:CIty 更改为 dbpedia-owl:Settlement,您将再次看到伦敦。
    猜你喜欢
    • 2018-01-26
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 2012-01-23
    • 2012-11-03
    • 1970-01-01
    相关资源
    最近更新 更多