【问题标题】:OWL reasoning: alternative to NOTOWL 推理:NOT 的替代方案
【发布时间】:2014-05-21 10:17:24
【问题描述】:

我正在使用 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,它有一个PEGI_RATING id。 示例:

<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" .

我想创建一个规则来确定附加到VIDEOGAMEPEGI_RATINGPEGI_CONTENT_DESCRIPTORs 的最大年龄。

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

最终结果

所以最后我们有了一个工作函数。它确实做了应该做的事情。不过..

首先,我们有许多 Jena 格式的规则,它们为每个 PEGI_CONTENT_DESCRIPTOR 添加了一个特定的年龄。这纯粹是出于教学原因(即,表明我们可以使用推理器)。这行得通。当我添加这些规则时,我可以对我的模型执行 SPARQL 查询并获得正确的值。当我写我的模型时(正如 Rob Hall 在他的例子中指出的那样)PEGI_CONTENT_DESCRIPTORs 确实有一个年龄。它们看起来像这样:

<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_DESCRIPTORs。即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 语法。它们本身并不“猫头鹰”中。
  • 是的,我真的不知道有什么区别。 Afaik 我可以编写猫头鹰规则,但他们只需要遵守这个特定的语法吗?对吗?
  • 这些规则将特定于 Apache Jena。还有其他规则语法(如 SWRL)。您选择的语法反映了将在幕后解释它们的推理器。 OWL 推理是通过使用 Jena 规则在 Jena 中实现的。这个推理是基于通用 RDF 数据的。如果您编写一个新的 Jena 规则并将其添加到包含 OWL 规则的规则集中,那么您将使用 owl 和您的额外规则进行推理。规则本身不会附加到您的文档中,也不会以猫头鹰的形式表达。这是一个小词汇,不会影响问题的答案。
  • 感谢您的详细说明!我很感激!
  • 关于您的编辑:您执行内置命令的规则是否已更改?我在 Jena 中遇到过似乎是一个错误,如果我的内置函数是我的规则正文中的第一个子句,那么我的上下文显示为空。我还会看看你当前的实现。

标签: jena owl jena-rules


【解决方案1】:

这与现有问题非常相似:Giving array as parameter to jena builtin。在开始之前,请注意使用 SPARQL 查询识别此元素非常容易。

在耶拿,您可以实现类似于以下的规则:

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

开始编辑

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

结束编辑

这要求您随后 implement a 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");

【讨论】:

  • 这似乎正是我所需要的。但是,我有一个问题。如果年龄可以从 PEGIRATING 立即访问,那么您的示例应该有效。但是,我需要按顺序排列年龄:VIDEOGAME 有 1 个PEGI_RATING_id,它有多个PEGI_CONTENT_DESCRIPTORs,而AGE 又是一个AGE。所以我也需要从每个描述符中获取该值。我正在玩代码,但直到现在它似乎还没有工作。不过我会继续努力的:)
  • 看起来你做对了。我能想到的唯一一件事是我以前在做同样的事情时遇到的耶拿的视图行为。
  • 感谢此代码!它启动了我们,一天后我们终于弄明白了。非常感谢您的时间和努力! :)
  • 另一个注意事项:如果推断与评级相关的年龄的三元组,那么在运行此规则时它们可能不可用。这是因为提供这些三元组的规则可能尚未触发,并且此内置函数的先决条件中没有任何内容迫使它们全部触发。可能有意义的一件事是在后向链接规则的上下文中实现这个特定的内置规则,并将前向链接规则保留为添加年龄的规则。然后,当通过反向链接规则查找时,年龄将可用。
猜你喜欢
  • 1970-01-01
  • 2013-05-29
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
  • 2023-01-19
  • 2011-06-08
  • 1970-01-01
  • 2021-04-26
相关资源
最近更新 更多