OWL推理:可以选择NOT



我正在使用OWL规则在JENA做一个项目。

在我的本体中我有一个名为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,它的id是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的最大年龄,附加到VIDEOGAMEPEGI_RATING

在Prolog中我会这样做:

 [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)]

最终结果

最后我们得到了一个有效的函数。它做的正是它应该做的。然而. .

首先,我们有一些耶拿格式的规则,为每个PEGI_CONTENT_DESCRIPTOR添加特定的年龄。这纯粹是出于说教的原因(即,表明我们可以使用推理器)。这个作品。当我添加这些规则时,我可以对我的模型执行SPARQL查询,并获得适当的值。当我写我的模型时(如Rob Hall在他的例子中指出的),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评级Id: ?game vocab:VIDEOGAME_pegiRatingRatingId ?pegiId

我们希望按照如下方式执行Jena Builtin:

minimumPegiAge(?pegiID, ?age)
为了达到这个目的,我们有下面的函数:它确实有效。然而,由于某种奇怪的原因,context.find(pegiID, has_descriptor.asNode(), Node.ANY);似乎没有迭代两个特定的PEGI_DESCRIPTOR s。即SexViolence。如前所述,它们存在于推断模型中,并且从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());
}

这与现有的问题非常相似:将数组作为参数提供给jena内置。在开始之前,需要注意的是,使用SPARQL查询标识这个元素是非常容易的。

在Jena中,您可以实现类似于以下的规则:

[Age: 
  (?game urn:ex:hasRating ?pegiID) 
  minPegiAge(?pegiID ?age) 
  -> 
  (?game urn:ex:age ?age)]

开始编辑

非常重要的是,您的规则以一些通用的三重模式开始,而不是自定义内置(在本例中为minPegiAge)。我遇到了一个问题,其中RuleContext提供给我的内置从RuleContext#find(...)返回任何东西。此外,我的规则上下文的InfGraph(以及Graph)都是空图,与实际的InfModel没有关联。一旦规则被更改为包含一些通用的三重模式作为开始模式,那么与RuleContext相关联的InfGraphInfModel将返回的InfGraph是相同的。

结束编辑

这需要你实现一个Jena内置函数来计算最小值。在内置中,您需要使用可用的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");

最新更新