Add support for snak location constraints
This commit is contained in:
parent
142eeabfeb
commit
283661956b
@ -53,6 +53,30 @@
|
|||||||
"unsourced-statements": {
|
"unsourced-statements": {
|
||||||
"title": "Statements without references.",
|
"title": "Statements without references.",
|
||||||
"body": "Most statements should have references. You can add them easily in the schema."
|
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,20 @@ public class ConstraintFetcher {
|
|||||||
public static String INVERSE_CONSTRAINT_QID = "Q21510855";
|
public static String INVERSE_CONSTRAINT_QID = "Q21510855";
|
||||||
public static String INVERSE_PROPERTY_PID = "P2306";
|
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 SINGLE_VALUE_CONSRAINT_QID = "Q19474404";
|
||||||
public static String DISTINCT_VALUES_CONSRAINT_QID = "Q21502410";
|
public static String DISTINCT_VALUES_CONSRAINT_QID = "Q21502410";
|
||||||
public static String TYPE_CONSTRAINT_QID = "Q21503250";
|
public static String TYPE_CONSTRAINT_QID = "Q21503250";
|
||||||
@ -73,6 +87,27 @@ public class ConstraintFetcher {
|
|||||||
return null;
|
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
|
* Returns a single constraint for a particular type and a property, or null
|
||||||
* if there is no such constraint
|
* if there is no such constraint
|
||||||
|
@ -8,6 +8,7 @@ import org.openrefine.wikidata.qa.scrutinizers.EditScrutinizer;
|
|||||||
import org.openrefine.wikidata.qa.scrutinizers.FormatConstraintScrutinizer;
|
import org.openrefine.wikidata.qa.scrutinizers.FormatConstraintScrutinizer;
|
||||||
import org.openrefine.wikidata.qa.scrutinizers.InverseConstraintScrutinizer;
|
import org.openrefine.wikidata.qa.scrutinizers.InverseConstraintScrutinizer;
|
||||||
import org.openrefine.wikidata.qa.scrutinizers.NewItemScrutinizer;
|
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.SelfReferentialScrutinizer;
|
||||||
import org.openrefine.wikidata.qa.scrutinizers.UnsourcedScrutinizer;
|
import org.openrefine.wikidata.qa.scrutinizers.UnsourcedScrutinizer;
|
||||||
import org.openrefine.wikidata.schema.ItemUpdate;
|
import org.openrefine.wikidata.schema.ItemUpdate;
|
||||||
@ -31,6 +32,7 @@ public class EditInspector {
|
|||||||
register(new InverseConstraintScrutinizer());
|
register(new InverseConstraintScrutinizer());
|
||||||
register(new SelfReferentialScrutinizer());
|
register(new SelfReferentialScrutinizer());
|
||||||
register(new UnsourcedScrutinizer());
|
register(new UnsourcedScrutinizer());
|
||||||
|
register(new RestrictedPositionScrutinizer());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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()) {
|
while(snaks.hasNext()) {
|
||||||
Snak snak = snaks.next();
|
Snak snak = snaks.next();
|
||||||
scrutinize(snak, entityId, added);
|
scrutinize(snak, entityId, added);
|
||||||
|
@ -27,4 +27,22 @@ public class ConstraintFetcherTests {
|
|||||||
public void testGetInverseConstraint() {
|
public void testGetInverseConstraint() {
|
||||||
Assert.assertEquals(fetcher.getInversePid("P361"), "P527");
|
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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user