Рассуждение о сове: альтернатива НЕ
Я делаю проект в JENA, используя правила OWL.
В моей онтологии у меня есть сущность с именем PEGI_RATING
, PEGI_RATING
может иметь несколько дескрипторов.
Пример:
<http://localhost:2020/PEGI_RATING/6>
a vocab:PEGI_RATING ;
rdfs:label "PEGI_RATING #6" ;
vocab:PEGI_RATING_age
16 ;
vocab:PEGI_RATING_has_PEGI_CONTENT_DESCRIPTOR
<http://localhost:2020/PEGI_CONTENT_DESCRIPTOR/Online> ,
<http://localhost:2020/PEGI_CONTENT_DESCRIPTOR/Violence> ,
<http://localhost:2020/PEGI_CONTENT_DESCRIPTOR/Bad_Language> ;
vocab:PEGI_RATING_ratingId
6 .
Теперь я хочу написать правило в OWL, которое устанавливает возраст каждого PEGI_RATING
, Я знаю, что это уже там, но необходимо показать, что я знаю, как использовать мыслитель.
Теперь к дескриптору контента прикреплен возраст. Я делаю это по следующему правилу:
[AgeLimit:
(?descr rdf:type vocab:PEGI_CONTENT_DESCRIPTOR)
(?descr vocab:PEGI_CONTENT_DESCRIPTOR_contentDescriptor "Sex")
->
(?descr vocab:PEGI_CONTENT_DESCRIPTOR_inf_age_limit "16"^^xsd:integer)
]
Итак, наконец, у меня есть VIDEO_GAME
который имеет PEGI_RATING
Я бы. Пример:
<http://localhost:2020/VIDEOGAME/Grand_Theft_Auto_IV>
a vocab:VIDEOGAME ;
rdfs:label "VIDEOGAME #Grand Theft Auto IV" ;
vocab:VIDEOGAME_EsrbRatingCategoryCategory
<http://localhost:2020/ESRB_RATING_CATEGORY/M> ;
vocab:VIDEOGAME_gameplayRulesGameplayRulesId
<http://localhost:2020/GAMEPLAY_RULES/3> ;
vocab:VIDEOGAME_has_SIDE_GOAL
<http://localhost:2020/SIDE_GOAL/Complete_all_missions.> ;
vocab:VIDEOGAME_onlineMultiplayer
"false"^^xsd:boolean ;
vocab:VIDEOGAME_pegiRatingRatingId
<http://localhost:2020/PEGI_RATING/3> ;
vocab:VIDEOGAME_summary
"For Niko Bellic, fresh off the boat from Europe, it is the hope he can escape his past. For his cousin, Roman, it is the vision that together they can find fortune in Liberty City, gateway to the land of opportunity. As they slip into debt and are dragged into a criminal underworld by a series of shysters, thieves and sociopaths, they discover that the reality is very different from the dream in a city that worships money and status, and is heaven for those who have them and a living nightmare for those who don't." ;
vocab:VIDEOGAME_title
"Grand Theft Auto IV" .
Я хочу создать правило, определяющее максимальный возраст PEGI_CONTENT_DESCRIPTOR
ы, которые прикреплены к PEGI_RATING
из VIDEOGAME
,
В Прологе я бы сделал что-то вроде этого:
[Age:
(?gameRelease rdf:type vocab:GAME_RELEASE)
(?gameRelease vocab:GAME_RELEASE_videogameTitle ?game)
(?game vocab:VIDEOGAME_pegiRatingRatingId ?pegiID)
(?pegiID vocab:PEGI_RATING_has_PEGI_CONTENT_DESCRIPTOR ?descriptor)
(?descriptor vocab:PEGI_CONTENT_DESCRIPTOR_inf_age_limit ?age)
(?descriptor vocab:PEGI_CONTENT_DESCRIPTOR_inf_age_limit ?age2)
not(lessThan(?age, ?age2))
->
(?game vocab:VIDEOGAME_inf_minimumAge ?age)]
Но так как у OWL, похоже, нет отрицания из-за неудачи, я не знаю, как ее решить.
До сих пор я пробовал следующее правило без успеха:
[Age:
(?gameRelease rdf:type vocab:GAME_RELEASE)
(?gameRelease vocab:GAME_RELEASE_videogameTitle ?game)
(?game vocab:VIDEOGAME_pegiRatingRatingId ?pegiID)
(?pegiID vocab:PEGI_RATING_has_PEGI_CONTENT_DESCRIPTOR ?descriptor)
(?descriptor vocab:PEGI_CONTENT_DESCRIPTOR_inf_age_limit ?age)
(?descriptor vocab:PEGI_CONTENT_DESCRIPTOR_inf_age_limit ?age2)
greaterThan(?age, ?age2)
->
(?game vocab:VIDEOGAME_inf_minimumAge ?age)]
КОНЕЧНЫЙ РЕЗУЛЬТАТ
Итак, наконец, у нас есть рабочая функция. Он делает именно то, что должен делать. Тем не мение..
Прежде всего, у нас есть ряд правил в формате Jena, которые добавляют определенный возраст каждому PEGI_CONTENT_DESCRIPTOR
, Это чисто по дидактическим причинам (т. Е. Показывает, что мы можем использовать рассуждения). Это работает. Когда я добавляю эти правила, я могу выполнять SPARQL-запросы к моей модели и получать правильные значения. Когда я делаю запись своей модели (как Роб Холл указал в своем примере) PEGI_CONTENT_DESCRIPTOR
У них действительно есть возраст. Они выглядят так:
<http://local.host.com:2020/PEGI_CONTENT_DESCRIPTOR/Violence>
a vocab:PEGI_CONTENT_DESCRIPTOR ;
rdfs:label "PEGI_CONTENT_DESCRIPTOR #Violence" ;
vocab:PEGI_CONTENT_DESCRIPTOR_contentDescriptor
"Violence" ;
vocab:PEGI_CONTENT_DESCRIPTOR_explanation
"May contain scenes of people getting injured or dying, often by use of weapons, whether realistically or in a fantastical or cartoonish manner. Also may contain gore and blood-letting." ;
vocab:PEGI_CONTENT_DESCRIPTOR_inf_age_limit
18 .
Помните, что видеоигра имеет идентификатор рейтинга PEGI: ?game vocab:VIDEOGAME_pegiRatingRatingId ?pegiId
,
Мы хотим выполнить Jena Builtin следующим образом:
minimumPegiAge(?pegiID, ?age)
Для этого у нас есть функция ниже. Это на самом деле работает. Однако по какой-то странной причине context.find(pegiID, has_descriptor.asNode(), Node.ANY);
кажется, не перебирать два конкретных PEGI_DESCRIPTOR
s. а именно Sex
а также Violence
, Как уже упоминалось, они присутствуют в предполагаемой модели и возвращаются из запросов SPARQL. Можем ли мы иметь дело с ошибкой? Или мы что-то упустили?
final Property has_age_limit =
ResourceFactory.createProperty("http://localhost:2020/vocab/PEGI_CONTENT_DESCRIPTOR_inf_age_limit");
final Property has_descriptor =
ResourceFactory.createProperty("http://localhost:2020/vocab/PEGI_RATING_has_PEGI_CONTENT_DESCRIPTOR");
// Create and Register a Builtin for Jena's rule system.
BuiltinRegistry.theRegistry.register(new BaseBuiltin() {
@Override
public String getName() {
return "minPegiAge";
}
@Override
public boolean bodyCall(final Node[] args, final int length, final com.hp.hpl.jena.reasoner.rulesys.RuleContext context) {
checkArgs(length, context);
final Node pegiID = getArg(0, args, context);
if( !getArg(1, args, context).isVariable() ){
return false;
}
// Should get all the descriptors for this PegiID.
ClosableIterator<Triple> x = context.find(pegiID, has_descriptor.asNode(), Node.ANY);
// Iterate over them.
final Iterator<Node> results =
new NiceIterator<Triple>()
.andThen(x) // Get all the descriptors
.mapWith(new Map1<Triple,Node>(){
@Override
public Node map1(Triple o) {
// o is a triple
// These triples are descriptors
// We need to get the age for these descriptors
System.out.println(o);
return o.getObject();
}});
if( !results.hasNext() ) {
return false;
}
Node min = null;
while(results.hasNext()) {
final Node pegiContentDescriptor = results.next();
System.out.println("DESCRIPTION: " + pegiContentDescriptor.toString());
ClosableIterator<Triple> y = context.find(pegiContentDescriptor, has_age_limit.asNode(), Node.ANY);
// Iterate over them.
final Iterator<Node> singleAge =
new NiceIterator<Triple>()
.andThen(y) // Get all the descriptors
.mapWith(new Map1<Triple,Node>(){
@Override
public Node map1(Triple o) {
// o is a triple
// These triples are descriptors
// We need to get the age for these descriptors
return o.getObject();
}});
if (singleAge.hasNext()) {
Node age = singleAge.next();
System.out.println("AGE: " + age.getLiteralValue());
if (min == null) {
min = age;
} else {
if (Util.compareTypedLiterals(min, age) < 0) {
min = age;
}
}
}
}
if (min == null) {
System.out.println("GEEN MINIMUM AGE GEVONDEN!");
} else {
System.out.println("MINIMUM: " + min.getLiteralValue());
}
context.getEnv().bind(getArg(1, args, context), min);
return true;
}
});
// Load TTL-file (full db dump!)
// Note: make sure the path containing the ttl file does not contain strange characters :D
// "-" and maybe spaces are not allowed
model = ModelFactory.createDefaultModel();
model.read(getClass().getResourceAsStream("/trivial-mapping-dump.ttl"), null, "TURTLE");
// Load the rules.
List<Rule> rules = Rule.rulesFromURL(getClass().getResource("/rules.txt").toString());
// Let the reasoner.. reason!
// Then add the triples existing due to rule firings to our base graph
GenericRuleReasoner r = new GenericRuleReasoner(rules);
r.setOWLTranslation(true); // not needed in RDFS case
r.setTransitiveClosureCaching(true);
r.setMode(GenericRuleReasoner.HYBRID);
InfModel infmodel = ModelFactory.createInfModel(r, model);
model.add(infmodel.getDeductionsModel());
}
1 ответ
Это очень похоже на существующий вопрос: предоставление массива в качестве параметра для встроенной функции jena. Прежде чем я начну, полезно отметить, что идентифицировать этот элемент с помощью запроса SPARQL чрезвычайно легко.
В Йене вы можете реализовать правило, подобное следующему:
[Age:
(?game urn:ex:hasRating ?pegiID)
minPegiAge(?pegiID ?age)
->
(?game urn:ex:age ?age)]
НАЧАТЬ РЕДАКТИРОВАТЬ
Чрезвычайно важно, чтобы ваше правило начиналось с некоторого общего тройного шаблона, а не с пользовательской встроенной функции (minPegiAge
в этом случае). Я столкнулся с проблемой, когда RuleContext
при условии, что мой встроенный ничего не возвращает от RuleContext#find(...)
, Кроме того, InfGraph
(так же как Graph
) для моего контекста правила оба пустых графика, которые не связаны с моим фактическим InfModel
, Как только правило изменено, чтобы включить некоторый общий тройной образец как начальный образец, тогда InfGraph
связано с RuleContext
та же InfGraph
какой твой InfModel
вернусь.
КОНЕЦ РЕДАКТИРОВАНИЯ
Это требует, чтобы вы затем реализовали Jena Builtin для расчета минимума. В пределах Builtin вам нужно будет использовать доступные RuleContext
для того, чтобы изучить ваш график и получить то, что вам нужно изучить минимум. В следующем примере создается встроенная функция, которая извлекает минимальное значение для определенного свойства типа данных.
// These properties will be used in the example, I define them for
// convenience here.
final Property hasRating = ResourceFactory.createProperty("urn:ex:hasRating");
final Property age = ResourceFactory.createProperty("urn:ex:age");
// Create and Register a Builtin for Jena's rule system.
BuiltinRegistry.theRegistry.register(new BaseBuiltin() {
@Override
public String getName() {
return "minPegiAge";
}
@Override
public boolean bodyCall( final Node[] args, final int length, final RuleContext context) {
checkArgs(length, context);
final Node rating = getArg(0, args, context);
if( !getArg(1, args, context).isVariable() ){
return false;
}
final Iterator<Node> results =
new NiceIterator<Triple>()
.andThen(context.find(rating, age.asNode(), Node.ANY))
.mapWith(new Map1<Triple,Node>(){
@Override
public Node map1(Triple o) {
return o.getObject();
}});
if( !results.hasNext() ) {
return false;
}
Node min = results.next();
while(results.hasNext()) {
final Node val = results.next();
if( Util.compareTypedLiterals(val, min) < 0 ) {
min = val;
}
}
context.getEnv().bind(getArg(1, args, context), min);
return true;
}
});
// Construct some sample data for this simplified version of
// your example scenario.
final Model rawData = ModelFactory.createDefaultModel();
final Resource game = rawData.createResource("urn:ex:theGame");
final Resource rating = rawData.createResource("urn:ex:theRating");
game.addProperty(hasRating, rating);
rating.addLiteral(age, 15);
rating.addLiteral(age, 14);
// Construct a simplified version of the rule that you use
// in order to identify when the minimum age needs to be
// detected.
final String rules =
"[Age: \n"+
" (?game urn:ex:hasRating ?pegiID) \n"+
" minPegiAge(?pegiID ?age) \n"+
" -> \n"+
" (?game urn:ex:age ?age)]";
final Reasoner reasoner;
try( final BufferedReader src = new BufferedReader(new StringReader(rules)) ) {
reasoner = new GenericRuleReasoner(Rule.parseRules(Rule.rulesParserFromReader(src)));
}
final InfModel inf = ModelFactory.createInfModel(reasoner, rawData);
// Write the model, now including a minimum age triple associated with
// the game rather than the various pe
inf.write(System.out, "TTL");