Предоставление массива в качестве параметра встроенной функции Jena

Мне нужно создать новый встроенный модуль для Jena. С этим я хотел бы иметь возможность извлечь минимальную дату, откуда она есть. Мне просто интересно, можно ли передать класс данных встроенному вместо одного параметра.

Вот bodyCall моей функции:

         @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;
        }     
    });

Это мое простое правило:

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

Даю на встроенные три параметра. Два на вход и один на выход. Моя идея заключается в использовании двух переменных: ?c и ?d. В обоих из них есть дата рождения. Я хотел бы получить первую запись из ?c и следующую запись из ?d. Но, похоже, Йена каждый раз делает первую запись.

Возможно ли с помощью Java сказать, что мне нужна вторая запись и прокручивать результаты?

Например, моя онтология состоит из двух дат: 1)1992-04-13T00:00:00.0; 2)1988-04-25T00:00:00.0

Я хочу иметь 1) в? c и 2) в? d, а затем сделать алгоритм, чтобы получить минимум между ними.

PS: В приведенном выше «bodyCall» я пытаюсь получить максимум между датами, которые я даю правилу. Он отлично работает для этой цели.

Спасибо вам всем.


person user3563844    schedule 08.05.2014    source источник
comment
Можете ли вы предоставить больше информации о сценарии? Пожалуйста, предоставьте минимальный пример, который может быть выполнен, включая желаемые входные и выходные данные. Некоторые потенциальные решения могут вообще не использовать встроенные функции (например, использование запроса SPARQL).   -  person Rob Hall    schedule 09.05.2014
comment
Привет! Да, ты получил то, что я хочу сделать. Я привожу вам пример. У меня есть данные этого класса: 1) 1992-12-01 2) 1993-20-02 3) 2000-18-01 4) 1995-15-04 5) 2014-01-01 6) 1999-23-05 минимум в этом наборе значений будет 1995-15-04.   -  person user3563844    schedule 09.05.2014
comment
Что ж, в моем классе есть тип Person, у которого в качестве свойства данных указан день рождения. Например, я хотел бы извлечь минимальное значение (дня рождения) из всех людей в этом классе. Возможно ли это с помощью первого метода, который вы мне объяснили?   -  person user3563844    schedule 09.05.2014


Ответы (1)


При реализации bodyCall(Node[], int, RuleContext) или headAction(Node[], int, RuleContext) в рамках реализации Builtin, вы задан массив аргументов, который представляет аргументы встроенной функции. Как правило, вы можете передать любое количество переменных во встроенную функцию (не только одну).

Вольно похоже (и вы можете исправить меня, если я неправильно истолковал ваш вопрос), что вы хотите работать над некоторым выражением класса, чтобы получить нужные вам данные. Если вашей общей целью является работа с «классом данных», то для этого есть несколько способов.

  1. (самый простой) Сформулируйте выражение вашего класса в виде утверждений в теле правила. Это гарантирует, что ваша встроенная функция будет передана только лицам соответствующего класса. Объединение в цепочку нескольких предварительных условий может позволить вам работать только с определенными людьми («класс данных»).

  2. (потенциально нетривиально) Если вы хотите, чтобы ваша встроенная функция работала с классом, используйте RuleContext, переданный вашему bodyCall(...) или headAction(...), чтобы найти людей, которые удовлетворяют вашему выражению класса (вызвав RuleContext#find(...) или какой-либо другой метод ).

В качестве примера предположим, что мы хотели воздействовать на каждого члена класса urn:ex:Question. В первом решении мы сформулируем правило, подобное следующему:

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

Это гарантирует, что мы будем работать с каждым экземпляром urn:ex:Question. Примером второго решения может быть передача выражения класса вашей встроенной функции напрямую. В вашем вопросе не указано, как вы бы определили рассматриваемый класс, поэтому я произвольно предположу, что вас интересуют классы, которые являются rdfs:subClassOf urn:ex:Question.

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

В этом случае вам нужно будет как-то работать с вашим «классом данных» внутри вашего встроенного кода. Как упоминалось ранее, для этого потенциально можно использовать RuleContext.

ИЗМЕНИТЬ

Предположим, что у вас есть 40 человек типа urn:ex:Question, и у каждого человека есть свойство urn:ex:dateSubmitted, указывающее, когда оно было отправлено. Это может быть довольно тривиально решено с помощью запроса SPARQL:

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

Редактировать 2 На основе новой информации в вашем обновлении вы, вероятно, можете просто изменить свой основной вызов, чтобы он выглядел следующим образом:

@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;
}
person Rob Hall    schedule 08.05.2014
comment
Кажется, это не работает. Сравнение производится по одному и тому же значению. Если n1 — это 1992-03-03, n2 по-прежнему 1992-03-03. Это потому, что я не знаю, как я могу сканировать элементы в моем правиле выше. - person user3563844; 12.05.2014
comment
Я думаю, что единственный способ - использовать SPARQL Query, чтобы делать то, что я хочу. - person user3563844; 12.05.2014