Add scrutinizer for allowed and mandatory qualifiers

This commit is contained in:
Antonin Delpeuch 2018-01-09 19:19:23 +00:00
parent 283661956b
commit 316ee86e1a
5 changed files with 141 additions and 2 deletions

View File

@ -77,6 +77,14 @@
"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."
},
"missing-mandatory-qualifiers": {
"title": "Missing mandatory qualifiers.",
"body": "Your statements are missing qualifiers, it would be good to add them."
},
"disallowed-qualifiers": {
"title": "Disallowed qualifiers.",
"body": "Some of your qualifiers are incompatible with the statements that they qualify. Please check your schema."
}
}
}

View File

@ -2,6 +2,7 @@ package org.openrefine.wikidata.qa;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -11,6 +12,7 @@ import org.wikidata.wdtk.datamodel.interfaces.EntityDocument;
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
import org.wikidata.wdtk.datamodel.interfaces.ItemIdValue;
import org.wikidata.wdtk.datamodel.interfaces.PropertyDocument;
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
import org.wikidata.wdtk.datamodel.interfaces.Snak;
import org.wikidata.wdtk.datamodel.interfaces.SnakGroup;
import org.wikidata.wdtk.datamodel.interfaces.Statement;
@ -42,8 +44,8 @@ public class ConstraintFetcher {
// 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 ALLOWED_QUALIFIERS_CONSTRAINT_QID = "Q21510851";
public static String ALLOWED_QUALIFIERS_CONSTRAINT_PID = "P2306";
public static String MANDATORY_QUALIFIERS_CONSTRAINT_QID = "Q21510856";
public static String MANDATORY_QUALIFIERS_CONSTRAINT_PID = "P2306";
@ -108,6 +110,32 @@ public class ConstraintFetcher {
return getSingleConstraint(pid, USED_ONLY_AS_REFERENCE_CONSTRAINT_QID) != null;
}
/**
* Get the list of allowed qualifiers (as property ids) for this property (null if any)
*/
public Set<PropertyIdValue> allowedQualifiers(PropertyIdValue pid) {
List<SnakGroup> specs = getSingleConstraint(pid.getId(), ALLOWED_QUALIFIERS_CONSTRAINT_QID);
if (specs != null) {
List<Value> properties = findValues(specs, ALLOWED_QUALIFIERS_CONSTRAINT_PID);
return properties.stream().map(e -> (PropertyIdValue) e).collect(Collectors.toSet());
}
return null;
}
/**
* Get the list of mandatory qualifiers (as property ids) for this property (null if any)
*/
public Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue pid) {
List<SnakGroup> specs = getSingleConstraint(pid.getId(), MANDATORY_QUALIFIERS_CONSTRAINT_QID);
if (specs != null) {
List<Value> properties = findValues(specs, MANDATORY_QUALIFIERS_CONSTRAINT_PID);
return properties.stream().map(e -> (PropertyIdValue) e).collect(Collectors.toSet());
}
return 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.QualifierCompatibilityScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.RestrictedPositionScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.SelfReferentialScrutinizer;
import org.openrefine.wikidata.qa.scrutinizers.UnsourcedScrutinizer;
@ -33,6 +34,7 @@ public class EditInspector {
register(new SelfReferentialScrutinizer());
register(new UnsourcedScrutinizer());
register(new RestrictedPositionScrutinizer());
register(new QualifierCompatibilityScrutinizer());
}
/**

View File

@ -0,0 +1,76 @@
package org.openrefine.wikidata.qa.scrutinizers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.openrefine.wikidata.qa.ConstraintFetcher;
import org.wikidata.wdtk.datamodel.interfaces.EntityIdValue;
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
import org.wikidata.wdtk.datamodel.interfaces.Statement;
/**
* A scrutinizer that checks the compatibility of the qualifiers
* and the property of a statement, and looks for mandatory qualifiers.
* @author antonin
*
*/
public class QualifierCompatibilityScrutinizer extends StatementScrutinizer {
private ConstraintFetcher _fetcher;
private Map<PropertyIdValue, Set<PropertyIdValue>> _allowedQualifiers;
private Map<PropertyIdValue, Set<PropertyIdValue>> _mandatoryQualifiers;
public QualifierCompatibilityScrutinizer() {
_fetcher = new ConstraintFetcher();
_allowedQualifiers = new HashMap<>();
_mandatoryQualifiers = new HashMap<>();
}
protected boolean qualifierIsAllowed(PropertyIdValue statementProperty, PropertyIdValue qualifierProperty) {
Set<PropertyIdValue> allowed = null;
if (_allowedQualifiers.containsKey(statementProperty)) {
allowed = _allowedQualifiers.get(statementProperty);
} else {
allowed = _fetcher.allowedQualifiers(statementProperty);
_allowedQualifiers.put(statementProperty, allowed);
}
return allowed == null || allowed.contains(qualifierProperty);
}
protected Set<PropertyIdValue> mandatoryQualifiers(PropertyIdValue statementProperty) {
Set<PropertyIdValue> mandatory = null;
if (_mandatoryQualifiers.containsKey(statementProperty)) {
mandatory = _mandatoryQualifiers.get(statementProperty);
} else {
mandatory = _fetcher.mandatoryQualifiers(statementProperty);
if (mandatory == null) {
mandatory = new HashSet<>();
}
_mandatoryQualifiers.put(statementProperty, mandatory);
}
return mandatory;
}
@Override
public void scrutinize(Statement statement, EntityIdValue entityId, boolean added) {
PropertyIdValue statementProperty = statement.getClaim().getMainSnak().getPropertyId();
Set<PropertyIdValue> qualifiers = statement.getClaim().getQualifiers().
stream().map(e -> e.getProperty()).collect(Collectors.toSet());
Set<PropertyIdValue> missingQualifiers = mandatoryQualifiers(statementProperty)
.stream().filter(p -> !qualifiers.contains(p)).collect(Collectors.toSet());
Set<PropertyIdValue> disallowedQualifiers = qualifiers
.stream().filter(p -> !qualifierIsAllowed(statementProperty, p)).collect(Collectors.toSet());
if( !missingQualifiers.isEmpty()) {
warning("missing-mandatory-qualifiers");
}
if (!disallowedQualifiers.isEmpty()) {
warning("disallowed-qualifiers");
}
}
}

View File

@ -2,14 +2,24 @@ package org.openrefine.wikidata.qa;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.wikidata.wdtk.datamodel.helpers.Datamodel;
import org.wikidata.wdtk.datamodel.interfaces.PropertyIdValue;
import java.util.regex.Pattern;
public class ConstraintFetcherTests {
private ConstraintFetcher fetcher;
private PropertyIdValue headOfGovernment;
private PropertyIdValue startTime;
private PropertyIdValue endTime;
public ConstraintFetcherTests() {
fetcher = new ConstraintFetcher();
headOfGovernment = Datamodel.makeWikidataPropertyIdValue("P6");
startTime = Datamodel.makeWikidataPropertyIdValue("P580");
endTime = Datamodel.makeWikidataPropertyIdValue("P582");
}
@Test
@ -45,4 +55,19 @@ public class ConstraintFetcherTests {
Assert.assertTrue(fetcher.isForValuesOnly("P6"));
Assert.assertFalse(fetcher.isForValuesOnly("P854"));
}
@Test
public void testAllowedQualifiers() {
Assert.assertTrue(fetcher.allowedQualifiers(headOfGovernment).contains(startTime));
Assert.assertTrue(fetcher.allowedQualifiers(headOfGovernment).contains(endTime));
Assert.assertFalse(fetcher.allowedQualifiers(headOfGovernment).contains(headOfGovernment));
Assert.assertNull(fetcher.allowedQualifiers(startTime));
}
@Test
public void testMandatoryQualifiers() {
Assert.assertTrue(fetcher.mandatoryQualifiers(headOfGovernment).contains(startTime));
Assert.assertFalse(fetcher.mandatoryQualifiers(headOfGovernment).contains(endTime));
Assert.assertNull(fetcher.allowedQualifiers(startTime));
}
}