Рассуждение о сове: альтернатива НЕ

Я делаю проект в 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_DESCRIPTORs. а именно 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");
Другие вопросы по тегам