Giving array as parameter to a Jena built-in

2019-09-01 16:00发布

问题:

I need to create a new built-in for Jena. With this one I would like to be able to extract the minimum date from where it is. I just wondering if it is possible to give a class of datas to a built-in instead of just one parameter.

Here is the bodyCall of my function :

         @Override
         public boolean bodyCall(Node[] args, int length, RuleContext context) {
            System.out.println("Entra");
            checkArgs(length, context);
            BindingEnvironment env = context.getEnv();
            Node n1 = getArg(0, args, context);
            Node n2 = getArg(1, args, context);
            //int count = 0;
            //do{
            //System.out.println("RULE"+context.getEnv().getGroundVersion(n2).getLiteralLexicalForm()); count ++;}while(count <2);
            System.out.println("Date 1: " + n1 + " and Date 2: " + n2);
            if (n1.isLiteral() && n2.isLiteral()) {
                Object v1 = n1.getLiteralValue();
                Object v2 = n2.getLiteralValue();
                Node max = null;
                if (v1 instanceof XSDDateTime && v2 instanceof XSDDateTime) {

                    XSDDateTime nv1 = (XSDDateTime) v1;
                    XSDDateTime nv2 = (XSDDateTime) v2;


                    Calendar data1 = new GregorianCalendar (nv1.getYears(), nv1.getMonths(), nv1.getDays());
                    Calendar data2 = new GregorianCalendar (nv2.getYears(), nv2.getMonths(), nv2.getDays());

                    SimpleDateFormat df = new SimpleDateFormat();
                    df.applyPattern("yyyy-dd-MM");

                    if (data1.compareTo(data2) > 0)
                    {
                        System.out.println("la data piu' grande e' DATA1: " +df.format(data1.getTime()));
                        max = args[0];
                    }

                    else
                    {
                        max = args[1];
                        System.out.print("la data piu' grande e' DATA1: " +df.format(data1.getTime()));
                    }

                      return env.bind(args[2], max);
                }
              }
             // Doesn't (yet) handle partially bound cases
             return false;
        }     
    });

This is my simple rule:

@prefix ex: http://www.semanticweb.org/prova_rules_M#
@prefix rdfs:   <http://www.w3.org/2000/01/rdf-schema#> .
[maxDate:
         (?p rdf:type ex:Persona)
         (?p http://www.semanticweb.org/prova_rules_M/persona#data_nascita ?c)
         (?p http://www.semanticweb.org/prova_rules_M/persona#data_nascita ?d)
         maxDate(?c,?d,?x)
         -> print(?x)
]

I give to the built-in three parameters. Two for input and one for output. My idea is using two varibles : ?c and ?d. In both of them there is a birthday date. I would like to get the first record from the ?c and the next record from the ?d. But, it looks like that Jena takes each time the first record.

Is it possible, by Java, telling that I want the second record and scroll the results ?

For example, my ontology is composed by two dates: 1)1992-04-13T00:00:00.0; 2)1988-04-25T00:00:00.0

I want to have 1) in ?c and 2) in ?d and then, make an algorithm to get the minimum between them.

ps : In the "bodyCall" above there is my try to get the maximum between to dates that I give to the rule. It works fine for this purpose.

Thank you all.

回答1:

When you implement bodyCall(Node[], int, RuleContext) or headAction(Node[], int, RuleContext) as part of implementing a Builtin, you are given an array of arguments that represents the arguments to to the builtin. In a rule, you can hand any number of variables to the the builtin (not only one).

It loosely seems like (and you can correct me if I am misinterpreting your question) that you are looking to work over some class expression in order to get the data that you need. If your overall goal is to operate on 'a class of data', then there are multiple ways to achieve this.

  1. (easiest) Formulate your class expression as statements within the body of the rule. This will ensure that your builtin is passed only individuals of the appropriate class. Chaining together multiple preconditions can allow you to only operate on certain individuals (a 'class of data').

  2. (potentially nontrivial) If you intend to have your builtin operate on a class, use the RuleContext passed to your bodyCall(...) or headAction(...) in order to find individuals that satisfy your class expression (by calling RuleContext#find(...) or some other method).

As an example, let's say that we wanted to act on each member of the class urn:ex:Question. In the first solution, we'd formulate a rule similar to the following:

[eachIndividual: (?x rdf:type urn:ex:Question) -> builtin(?x)]

This would ensure that we'd operate on every single instance of urn:ex:Question. An example of the second solution would be to pass the class expression to your builtin directly. Your question does not indicate how you would identify the class in question, so I will arbitrarily assume that you are interested in classes which are rdfs:subClassOf urn:ex:Question.

[eachSubclass: (x? rdfs:subClassof urn:ex:Question) -> builtin(?x)]

In this case, you would need to somehow operate on your 'class of data' within your builtin. As mentioned previously, you could potentially use the RuleContext to do so.

EDIT

Let us assume that you have 40 individuals of type urn:ex:Question, and each individual has a property urn:ex:dateSubmitted that indicates when it was submitted. This can be rather trivially solved using a SPARQL query:

SELECT ?post WHERE {
    ?post a urn:ex:Question .
    ?post urn:ex:dateSubmitted ?date .
}
ORDER BY ?date
LIMIT 1

Edit 2 Based on the new information in your update, you can probably just modify your body call to look like the following:

@Override
public boolean bodyCall( final Node[] args, final int length, final RuleContext context )
{
    checkArgs(length, context);
    final Node n1 = getArg(0, args, context);
    final Node n2 = getArg(1, args, context);

    if (n1.isLiteral() && n2.isLiteral()) {
        final Node max = Util.compareTypedLiterals(n1, n2) < 0 ? n2 : n1;
        return context.getEnv().bind(args[2], max);
    }
    return false;
}