Add support for snak location constraints

This commit is contained in:
Antonin Delpeuch 2018-01-09 14:13:42 +00:00
parent 142eeabfeb
commit 283661956b
6 changed files with 170 additions and 1 deletions

View File

@ -53,6 +53,30 @@
"unsourced-statements": {
"title": "Statements without references.",
"body": "Most statements should have references. You can add them easily in the schema."
},
"property-restricted-to-reference-found-in-mainsnak": {
"title": "Reference-only property used as statement.",
"body": "You are using in a statement a property that was designed to be used in references only."
},
"property-restricted-to-reference-found-in-qualifier": {
"title": "Reference-only property used as qualifier.",
"body": "You are using in a qualifier a property that was designed to be used in references only."
},
"property-restricted-to-qualifier-found-in-mainsnak": {
"title": "Qualifier-only property used as statement.",
"body": "You are using in a statement a property that was designed to be used in qualifiers only."
},
"property-restricted-to-qualifier-found-in-reference": {
"title": "Qualifier-only property used as reference.",
"body": "You are using in a reference a property that was designed to be used in qualifiers only."
},
"property-restricted-to-mainsnak-found-in-qualifier": {
"title": "Statement-only property used as qualifier.",
"body": "You are using in a qualifier a property that was designed to be used as a statement only."
},
"property-restricted-to-mainsnak-found-in-reference": {
"title": "Statement-only property used as reference.",
"body": "You are using in a reference a property that was designed to be used as a statement only."
}
}
}

View File

@ -34,6 +34,20 @@ public class ConstraintFetcher {
public static String INVERSE_CONSTRAINT_QID = "Q21510855";
public static String INVERSE_PROPERTY_PID = "P2306";
public static String USED_ONLY_AS_VALUES_CONSTRAINT_QID = "Q21528958";
public static String USED_ONLY_AS_QUALIFIER_CONSTRAINT_QID = "Q21510863";
public static String USED_ONLY_AS_REFERENCE_CONSTRAINT_QID = "Q21528959";
// The following constraints still need to be implemented:
public static String ALLOWED_QUALIFIERS_CONSRAINT_QID = "Q21510851";
public static String ALLOWED_QUALIFIERS_PID = "P2306";
public static String MANDATORY_QUALIFIERS_CONSTRAINT_QID = "Q21510856";
public static String MANDATORY_QUALIFIERS_CONSTRAINT_PID = "P2306";
public static String SINGLE_VALUE_CONSRAINT_QID = "Q19474404";
public static String DISTINCT_VALUES_CONSRAINT_QID = "Q21502410";
public static String TYPE_CONSTRAINT_QID = "Q21503250";
@ -73,6 +87,27 @@ public class ConstraintFetcher {
return null;
}
/**
* Is this property for values only?
*/
public boolean isForValuesOnly(String pid) {
return getSingleConstraint(pid, USED_ONLY_AS_VALUES_CONSTRAINT_QID) != null;
}
/**
* Is this property for qualifiers only?
*/
public boolean isForQualifiersOnly(String pid) {
return getSingleConstraint(pid, USED_ONLY_AS_QUALIFIER_CONSTRAINT_QID) != null;
}
/**
* Is this property for references only?
*/
public boolean isForReferencesOnly(String pid) {
return getSingleConstraint(pid, USED_ONLY_AS_REFERENCE_CONSTRAINT_QID) != null;
}
/**
* Returns a single constraint for a particular type and a property, or null
* if there is no such constraint

View File

@ -8,6 +8,7 @@ import org.openrefine.wikidata.qa.scrutinizers.EditScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.FormatConstraintScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.InverseConstraintScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.NewItemScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.RestrictedPositionScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.SelfReferentialScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.UnsourcedScrutinizer;
import org.openrefine.wikidata.schema.ItemUpdate;
@ -31,6 +32,7 @@ public class EditInspector {
register(new InverseConstraintScrutinizer());
register(new SelfReferentialScrutinizer());
register(new UnsourcedScrutinizer());
register(new RestrictedPositionScrutinizer());
}
/**

View File

@ -0,0 +1,90 @@
package org.openrefine.wikidata.qa.scrutinizers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.openrefine.wikidata.qa.ConstraintFetcher;
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
import org.wikidata.wdtk.datamodel.interfaces.Reference;
import org.wikidata.wdtk.datamodel.interfaces.Snak;
import org.wikidata.wdtk.datamodel.interfaces.Statement;
public class RestrictedPositionScrutinizer extends StatementScrutinizer {
protected enum SnakPosition {
MAINSNAK,
QUALIFIER,
REFERENCE
}
private Map<String, SnakPosition> _restrictedPids;
private Set<String> _unrestrictedPids;
private ConstraintFetcher _fetcher;
public RestrictedPositionScrutinizer() {
_restrictedPids = new HashMap<>();
_unrestrictedPids = new HashSet<>();
_fetcher = new ConstraintFetcher();
}
SnakPosition positionRestriction(String pid) {
if(_unrestrictedPids.contains(pid)) {
return null;
}
SnakPosition restriction = _restrictedPids.get(pid);
if (restriction != null) {
return restriction;
} else {
if (_fetcher.isForValuesOnly(pid)) {
restriction = SnakPosition.MAINSNAK;
} else if (_fetcher.isForQualifiersOnly(pid)) {
restriction = SnakPosition.QUALIFIER;
} else if (_fetcher.isForReferencesOnly(pid)) {
restriction = SnakPosition.REFERENCE;
}
// Cache these results:
if (restriction != null) {
_restrictedPids.put(pid, restriction);
} else {
_unrestrictedPids.add(pid);
}
return restriction;
}
}
@Override
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
// Skip the main snak
scrutinize(statement.getClaim().getMainSnak(), entityId, SnakPosition.MAINSNAK, added);
// Qualifiers
scrutinizeSnakSet(statement.getClaim().getAllQualifiers(), entityId, SnakPosition.QUALIFIER, added);
// References
for(Reference ref : statement.getReferences()) {
scrutinizeSnakSet(ref.getAllSnaks(), entityId, SnakPosition.REFERENCE, added);
}
}
protected void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, SnakPosition position, boolean added) {
while(snaks.hasNext()) {
Snak snak = snaks.next();
scrutinize(snak, entityId, position, added);
}
}
public void scrutinize(Snak snak, EntityIdValue entityId, SnakPosition position, boolean added) {
SnakPosition restriction = positionRestriction(snak.getPropertyId().getId());
if (restriction != null && position != restriction) {
String positionStr = position.toString().toLowerCase();
String restrictionStr = restriction.toString().toLowerCase();
warning("property-restricted-to-"+restrictionStr+"-found-in-"+positionStr);
}
}
}

View File

@ -38,7 +38,7 @@ public abstract class SnakScrutinizer extends StatementScrutinizer {
}
}
private void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, boolean added) {
protected void scrutinizeSnakSet(Iterator<Snak> snaks, EntityIdValue entityId, boolean added) {
while(snaks.hasNext()) {
Snak snak = snaks.next();
scrutinize(snak, entityId, added);

View File

@ -27,4 +27,22 @@ public class ConstraintFetcherTests {
public void testGetInverseConstraint() {
Assert.assertEquals(fetcher.getInversePid("P361"), "P527");
}
@Test
public void testOnlyReferences() {
Assert.assertTrue(fetcher.isForReferencesOnly("P854"));
Assert.assertFalse(fetcher.isForReferencesOnly("P2241"));
}
@Test
public void testOnlyQualifiers() {
Assert.assertTrue(fetcher.isForQualifiersOnly("P2241"));
Assert.assertFalse(fetcher.isForQualifiersOnly("P6"));
}
@Test
public void testOnlyValues() {
Assert.assertTrue(fetcher.isForValuesOnly("P6"));
Assert.assertFalse(fetcher.isForValuesOnly("P854"));
}
}