Как эффективно вычислить дизъюнктность с OWLAPI? - PullRequest
1 голос
/ 04 апреля 2020

Я профилирую свое приложение на основе OWLAPI, и единственное узкое место, которое я обнаружил, касалось вычисления дизъюнктивности . Я должен проверить, является ли каждый класс непересекающимся с другими классами и, если это заявлено или выведено .

Кажется, что это тяжело для вычисления, потому что в отличие от эквивалентность, которая основана на структуре данных Node (и это эффективно для извлечения данных), дизъюнктивность основана на NodeSet таким образом, я вынужден выполнять больше циклов , Вот процедура, которую я использую:

private void computeDisjointness(OWLClass clazz) {

    NodeSet<OWLClass> disjointSetsFromCls = reasoner.getDisjointClasses(clazz);
    for (Node<OWLClass> singleDisjoinSet : disjointSetsFromCls) {
        for (OWLClass item : singleDisjoinSet) {
             for (OWLDisjointClassesAxiom disjAxiom : ontology.getAxioms(AxiomType.DISJOINT_CLASSES)) {
                 if(disjAxiom.containsEntityInSignature(item))
                  {
                   //asserted
                  }
                  else
                  {
                  //derived
                  }
        }
    }
}

Как видите, узкое место задается циклами 3 для замедления приложения; Более того, процедура computeDisjointness выполняется для каждого класса онтологии.

Существует ли более эффективный способ получить несвязность и проверить, утверждены или получены аксиомы?

1 Ответ

2 голосов
/ 05 апреля 2020

Одной простой оптимизацией является перемещение ontology.getAxioms(AxiomType.DISJOINT_CLASSES) в вызывающий метод, а затем передача его в качестве параметра. Этот метод возвращает новый набор при каждом вызове, каждый раз с одним и тем же содержимым, так как вы не изменяете онтологию. Поэтому, если у вас есть N классов, вы создаете как минимум N идентичных наборов; больше, если многие классы фактически не пересекаются.

Оптимизация номер два: проверьте размер набора непересекающихся узлов. Размер 1 означает отсутствие разрыва, поэтому вы можете пропустить оставшуюся часть метода.

Оптимизация 3: отслеживать классы, которые вы уже посетили. Например, если у вас есть

A disjointWith B

, ваш код будет вызываться на A и циклически повторяться на A и B, затем вызываться на B и повторять вычисления. Сохраняйте набор посещенных классов, к которому вы добавляете все элементы в наборе непересекающихся узлов, и когда он станет B, вы также сможете пропустить вызов аргумента. Говоря об этом, я бы предположил, что вызов аргумента является фактически самым дорогим вызовом в этом методе. У вас есть данные профилирования, которые говорят иначе?

Оптимизация 4: Я не уверен, что этот код достоверно говорит вам, какие непересекающиеся аксиомы выведены, а какие утверждены. Вы могли бы иметь:

A disjointWith B
B disjointWith C

Разумник вернет {A, B, C} в ответ на запрос о несоответствии A. Вы найдете все три элемента в сигнатуре непересекающейся аксиомы и обнаружите, что мыслитель не сделал никаких выводов. Но аксиомы на входе не совпадают с аксиомами на выходе (многие рассуждения фактически запускают поглощение на входных аксиомах и преобразуют их во внутреннее представление, которое является аксиомой с тремя операндами). Итак, мое определение логического вывода и утверждения будет таким: набор узлов, возвращаемых рассуждателем, совпадает с набором операндов одной непересекающейся аксиомы. Чтобы проверить это условие, я бы взял все непересекающиеся аксиомы, выделил набор операндов и сохранил эти наборы в наборе наборов. Затем

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