2

This is the query that can be executed in https://query.wikidata.org, I am supposed to get only 17 values, but it returns 289 results (17 * 17 = 289). I want to get property value with its unit. I am specifying wdt:P2573 just to demonstrate the issue, in real application that property is a variable ?p.

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

SELECT * WHERE {
  wd:Q2 wdt:P2573 ?o.
  wd:Q2 rdfs:label ?entName.
  ?realAtt wikibase:directClaim wdt:P2573.
  ?realAtt rdfs:label ?attName.
  ?realAtt wikibase:propertyType ?wdDataType.

  OPTIONAL {
    ?realAtt wikibase:statementValue ?psv.
    ?realAtt wikibase:claim ?pp.
    wd:Q2 ?pp ?quantityNode.
    ?quantityNode ?psv ?wdv.
    ?wdv wikibase:quantityUnit ?unit.
    ?wdv wikibase:quantityAmount ?qAmount.
    BIND(?qAmount AS ?val)
  }
  BIND(COALESCE(?val, ?o) AS ?val)


  BIND(COALESCE(?unit, "") AS ?unit)
  FILTER(((LANG(?o)) = "en") || ((LANG(?o)) = "") || (!ISLITERAL(?o)))
  FILTER(((LANG(?attName)) = "en") || ((LANG(?attName)) = ""))
  FILTER(((LANG(?entName)) = "en") || ((LANG(?entName)) = ""))
}
logi-kal
  • 7,107
  • 6
  • 31
  • 43
William
  • 5,526
  • 6
  • 20
  • 42

1 Answers1

3

Simple values of truthy statements are not automagically connected with value nodes (class diagram).

Your MCVE should look like this:

SELECT * WHERE {
  wd:Q2 wdt:P2573 ?o.
  OPTIONAL {
    wd:Q2 p:P2573/psv:P2573 ?wdv.
    ?wdv wikibase:quantityUnit ?unit.
    ?wdv wikibase:quantityAmount ?qAmount.
    # FILTER( ?unit != wd:Q199 )
  }
}

Try it!

In the query above, the only joining condition of ?o and ?wdv is their relatedness to wd:Q2.
Hence, you obtain cartesian product of ?o and ?wdv bindings (right, 17×17 = 289).

The correct query should look like this:

SELECT * WHERE {
  wd:Q2 p:P2573/psv:P2573 ?wdv.
  OPTIONAL {
    ?wdv wikibase:quantityUnit ?unit.
    ?wdv wikibase:quantityAmount ?qAmount.
  }
}

Try it!

Update

The above query works for quantities only. Obviously, it doesn't work for times or globe coordinates. Moreover, sometimes statements don't have full values at all. For example, statements with string objects have simple values only. One should get simple values from statements and then try to get additional info from full values:

SELECT * {
  VALUES (?wd) {(wd:P2067)(wd:P1332)(wd:P1814)}
  ?wd wikibase:claim ?p;
      wikibase:statementProperty ?ps;
      wikibase:statementValue ?psv.
  wd:Q2 ?p ?wds.
  ?wds ?ps ?sv.
  OPTIONAL {
    ?wds ?psv ?wdv
    OPTIONAL {?wdv wikibase:quantityUnit ?unit.
    ?wdv wikibase:quantityAmount ?amount}
  }
}

Try it!

Overall, statements characteristics can be quite diverse. It is not very convenient to represent all these data in a table format. That is one of the reasons why RDF exists.

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
  • 1
    Thanks, now I understand more, from the diagram, can I confirm if I can always get value directly from Value Node and ignore the Simple Value. Whatever value in Simple Value, it will always exist in Value Node too right ? – William Apr 02 '18 at 10:38
  • No. For example, strings doesn't have full values: see [this](https://www.mediawiki.org/wiki/Wikibase/Indexing/RDF_Dump_Format#Value_representation). I supposed you are interested in quantities only. Otherwise, one should get simple values from *statement* (`wds:...`) and then try to get additional characteristics from the full value (`wdv:...`). – Stanislav Kralin Apr 02 '18 at 12:52
  • Like [this](https://query.wikidata.org/#SELECT%20%2a%20%7B%0A%20%20VALUES%20%28%3Fwd%29%20%7B%28wd%3AP2067%29%28wd%3AP1332%29%28wd%3AP1814%29%7D%0A%20%20%3Fwd%20wikibase%3Aclaim%20%3Fp%3B%0A%20%20%20%20wikibase%3AstatementProperty%20%3Fps%3B%0A%20%20%20%20wikibase%3AstatementValue%20%3Fpsv.%0A%20%20wd%3AQ2%20%3Fp%20%3Fwds.%0A%20%20%3Fwds%20%3Fps%20%3Fsv.%0A%20%20OPTIONAL%20%7B%0A%20%20%20%20%3Fwds%20%3Fpsv%20%3Fwdv%0A%20%20%20%20OPTIONAL%20%7B%3Fwdv%20wikibase%3AquantityUnit%20%3Funit.%0A%20%20%20%20%3Fwdv%20wikibase%3AquantityAmount%20%3Famount%7D%0A%20%20%7D%0A%7D). – Stanislav Kralin Apr 02 '18 at 12:55
  • Ahh ok, my mistake, I meant to say that whatever value of wdt:... there will always be a value in the wds: or wdv: right ? So that I can just read value from wds/wdv instead and ignore the value of wdt. Noted on the not always exist for wdv: – William Apr 02 '18 at 13:28
  • 1
    Yes, it is always possible to use the `p..:/ps:..` path. In some cases, it is possible to use the `p..:/psv:../wikibase..` path. Please note that there also exist the so-called *normalized values*. They are displayed on web pages and may be different from simple and full values. BTW, this should be hard to represent all these things in a table format. That's one of the reasons why Linked Data exists... – Stanislav Kralin Apr 02 '18 at 13:37
  • Hi, I have another similar problem here, according to the ttl format, I am suppose to get only 1 result, but it returns 8. If you can help too ? Thanks a lot. link on next comment. – William Apr 04 '18 at 09:26
  • [Here it is](https://query.wikidata.org/#select%20%2a%20WHERE%20%7Bwd%3AQ2%20p%3AP1332%20%3Fwds.%20%0A%20%20%3Fwds%20%3Fps%20%3Fwd%20.%0A%20%20%3FrealAtt%20wikibase%3Aclaim%20p%3AP1332%20%3B%0A%20%20wikibase%3AstatementValue%20%3Fpsv%3B%0A%20%20wikibase%3AstatementProperty%20%3Fps%20.%0A%20%20%20%20OPTIONAL%20%7B%0A%20%20%20%20%20%20%20%3Fwds%20%3Fpsv%20%3Fwdv%20.%0A%20%20%20%20%20%20%20%3Fwdv%20wikibase%3AgeoLatitude%20%3Flat%20%3B%0A%20%20%20%20%20%20%20wikibase%3AgeoLongitude%20%3Flng%20%3B%0A%20%20%20%20%20%20%20wikibase%3AgeoPrecision%20%3Fpre%20.%0A%20%20%20%20%7D%0A%7D) – William Apr 04 '18 at 09:29
  • @William, minify to `SELECT ?lat ?lng ?pre WHERE `. `"90.0"^^xsd:double` and `"90"^^xsd:decimal` are distinct values. See also https://stackoverflow.com/a/49015788/7879193 – Stanislav Kralin Apr 04 '18 at 09:37
  • That's helpful, it works now thanks. So I assume this is a bug in blazegraph ? – William Apr 04 '18 at 09:58
  • @William, this is rather an artefact of miscellaneous imports/exports: https://phabricator.wikimedia.org/T179228. I don't think that `DISTINCT` should involve type casting etc. – Stanislav Kralin Apr 04 '18 at 12:04