Невозможно использовать переменную, объявленную с помощью Ruta DECLARE

Я пытаюсь написать некоторые правила Ruta для фиксации отношений «есть-а» между вещами. У меня есть класс Relation, который включает в себя атрибуты entity1 и entity2, которые указывают на две вещи, связанные с отношением.

Насколько я понимаю, я должен «захватить» эти два элемента с аннотациями, которые ОБЪЯВЛЕНЫ, чтобы позже я мог установить их как атрибуты аннотации отношения.

Итак, мое правило гласит:

 DECLARE Token Thing1;
 DECLARE Token Thing2;

Но каким-то образом, когда я пытаюсь пометить токен как Thing1 или Thing2, Ruta сообщает мне, что он не может получить доступ к этому типу.

Вот тест, который иллюстрирует проблему

@Test
public void test__Ruta__BUG__DeclareNotWorking() throws UIMAException, IOException, URISyntaxException {
    final class RulesRunner {
        public void applyRules(JCas cas, String[] rules) throws AnalysisEngineProcessException, InvalidXMLException, ResourceInitializationException, ResourceConfigurationException, IOException, URISyntaxException {
            for (String aRule: rules) {
                Ruta.apply(cas.getCas(), aRule);
            }
        }
    }

    RulesRunner runner = new RulesRunner();

    JCas cas = JCasFactory.createJCas();
    cas.setDocumentText("A cat is a kind of mammal.");

    // Tokenize the string
    String[] rules = new String[] {
            "ANY{REGEXP(\"[a-zA-Z0-9]+\") -> Token};",
            "ANY{REGEXP(\"[^ a-zA-Z0-9]+\") -> Token};"
    };
    runner.applyRules(cas, rules);

    // Capture the "is-a" relation between 'cat' and 'mammal' and 'car' and 'vehicle'
    rules = new String[] {
        "DECLARE Token Thing1; \n" +
           "DECLARE Token Thing2; \n" +
           // This results in: 'not able to resolve type: Thing1'
           "Token{ -> MARK(Thing1)} " +
           "Token{REGEXP(\"is\") -> RutaNevermind}  " +
           "Token{REGEXP(\"a\") -> RutaNevermind}  " +
           "Token{REGEXP(\"kind\") -> RutaNevermind}  " +
           "Token{REGEXP(\"of\") -> RutaNevermind}  " +
           "Token{ -> MARK(Relation, 1, 6)}  " +
           ";" 
    };
    runner.applyRules(cas, rules);

    for (Relation aRelation: JCasUtil.select(cas, Relation.class)) {
        System.out.println("Got Relation="+aRelation.getCoveredText());
    }
}

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

DECLARE Thing1;
DECLARE Thing2;

а также

DECLARE Thing1 Token;
DECLARE Thing2 Token;

а также

DECLARE Token thing1; // Obviously, changed the MARK statement accordingly
DECLARE Token thing2;

person Alain Désilets    schedule 06.04.2017    source источник


Ответы (2)


Не нашел способ заставить работать пустые действия, но нашел обходной путь. По сути, у меня есть класс аннотаций RutaNull, и всякий раз, когда мне нужно использовать пустое действие, я буду использовать MARK(RutaNull). Но если у кого-то есть ответ на вопрос, как заставить пустые действия работать, я все равно хотел бы его услышать.

person Alain Désilets    schedule 07.04.2017
comment
Действия не требуются. Их можно просто опустить, но также нужно убрать -> с указанием на наличие действия. - person Peter Kluegl; 10.04.2017

Здесь нужно учитывать несколько вещей:

DECLARE объявляет не переменные, а тип UIMA. Объявление переменной для типа будет выглядеть так: TYPE myTypeVar;. Я предполагаю, что вы имели в виду не переменную в своем вопросе, а тип.

Система типов CAS в UIMA является статической после создания CAS. Правила рута не могут расширять его оператором DECLARE при выполнении правил, когда механизмы анализа обрабатывают CAS. В Ruta есть отдельная функция для создания описания системы типов сценария ruta, которое содержит описания типов для каждого объявления. Обычно это делается на уровне "компиляции", например, с помощью ruta-maven-plugin или Ruta Workbench. Если вам нужно использовать его программно, как в коде вашего вопроса, вы можете либо добавить тип вручную, либо использовать RutaDescriptorFactory. Вот некоторые код, как это работает. Если вы хотите создать CAS, используя фабрику uimaFIT, вы можете просто использовать созданное TypeSystemDescription в качестве аргумента.

Действия над элементами правила не требуются. Их можно просто опустить, но также нужно убрать стрелку ->. Вы также можете написать правило без единого действия, например, для использования его в качестве оператора запроса в представлении запросов Ruta Workbench.

Оператор DECLARE объявляет новые типы. Вы можете указать необязательный родительский тип для новых типов, который, конечно же, является супертипом нового типа. Если Thing1 — ваш новый тип, то DECLARE Thing1 Token; недействителен. но DECLARE Token Thing1; есть. DECLARE Thing1; устанавливает супертип uima.tcas.Annotation. Я бы не рекомендовал использовать Token в качестве супертипа.

Определение типа Relation в вопросе не дается. Этот тип уже существует? Если нет, применяется то же самое, что и для других типов: вам необходимо включить его в систему типов CAS.

Возможно, самое важное замечание: вам даже не нужно объявлять новый тип, что, возможно, позволит избежать вашей проблемы в целом. Существует несколько способов заполнить элементы аннотации другими аннотациями. В 1.4 Learning by Example часть документации рута, например, CREATE, GATHER, неявные действия, переменные, выражение метки. В основном это зависит от определения вашего Relation и от фактического варианта использования. В вашем примере правила могут выглядеть так (отношение является одним из ваших типов?, без экранированных кавычек):

//DECLARE Relation (Token source, Token target); just a comment how the Relation type is assumed to be defined
(t1:Token "is" "a" "kind" "of" t2:Token){-> Relation, Relation.source=t1, Relation.target=t2};

or...

Token "is" "a" "kind" "of" Token{-> GATHER(Relation,1,6,"source"=1,"target"=6)};

Вероятно, вам следует оптимизировать это правило, используя другие условия соответствия, FILTERTYPE или -PARTOF.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: я разработчик UIMA Ruta

person Peter Kluegl    schedule 10.04.2017