Робот
Устройство и подключениеУправляющее ПОЯзык BMLСловарь жестовSSSenderAPI робота
Когнитивный компонент
Обработка текстаПарсерМассивы текстовБаза разборов

Обработка массива текстов

С помощью парсера можно обрабатывать большие массивы текстовых файлов или источников RSS.

Запуск приложения

При запуске файла можно указывать параметры командной строки, например:

 @D:\parser\PipeDemo.exe ^
 --input-file="D:\parser\novost.txt" ^
 --input-encoding="utf-8" ^
 --rules-file="D:\parser\rules.xml" ^
 --mssqlrep-connectionstring="Data Source=SYNTAX.RRCKI.RU;Initial Catalog=Scenarios;User Id=sa;Password=REPLACE_PASSWORD" ^
 --pgsink-connection="Host=syntax.rrcki.ru;Port=5433;Username=postgres;Password=REPLACE_PASSWORD;Database=emotional" ^
 --morphmatchregex_pattern="C:\parser\patterns.xml"^
 --guesserweb-host="http://syntax.rrcki.ru:5000"^
 --guesserweb-ntop 10

Где

Параметр Описание
--input-file входящий файл: можно обрабатывать один текстовый файл за один запуск
--input-encoding кодировка входящего файла (default windows-1251) – Описание
--rules-file грамматика в формате syntXML
--mssqlrep-connectionstring строка подключения к базе MS SQL для получения граммем и семантических признаков
--pgsink-connection строка подключения к базе PostgreSQL для сохранения результатов разбора – Описание базы
--morphmatchregex_pattern файл разбора словоформ по регулярным выражениям
--guesserweb-host адрес работы системы разрабора словоформ по сходству («гессер»)
--guesserweb-ntop число возвращаемых вариантов разбора словоформ по сходству

Чтобы обработать несколько файлов, нужно запустить файл PipeDemo.exe для каждого из них. Для этого можно создать командный файл, который будет вызывать PipeDemo.exe для каждого файла из директории.

При запуске PipeDemo.exe выводит только сообщения о начале работы и о её окончании:

Emotional Agent Pipeline Parser.
Started              : 2018-09-24 16:37:18.09
Initialized          : 2018-09-24 16:37:19.91
Finished             : 2018-09-24 16:37:40.94

Проверка добавления в базу

Чтобы убедиться, что процесс разбора идёт, нужно задать вопрос к базе. Следующий запрос показывает максимальный идентификатор в таблицах. Если происходит запись в таблицы, то значения запроса при последовательных запусках будут расти.

SELECT 'sentences' base, MAX(id) maxid FROM sentences 
UNION ALL
SELECT 'syntax' base, MAX(id) maxid FROM syntax
UNION ALL
SELECT 'facts' base, MAX(id) maxid FROM facts

Возможный результат:

base maxid
sentences 2343552
syntax 267514
facts 4860259

Последняя запись в базе

Конечно, во время разбора интересно, что именно было добавлено в каждую таблицу. Следующий запрос показывает последнюю добавленную запись в каждой таблице:

-- что происходит?
-- по каждой таблице выводит последний процесс, id последнего элемента и хэш
-- при последовательных запусках позволяет следит за измнениями в базе, проверять, какие базы меняет последний процесс

(SELECT 'sentences' base, substring(meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' FOR 8) process, id, substring(hash::text for 5) hash
    , 'matcher: "' || (meta -> 'metadata' -> 'morphology_matcher' ->> 'version') || 
    '", guesser: "' || (meta -> 'metadata' -> 'morphology_guesser' ->> 'version') || 
    '", splitter: "' || (meta -> 'metadata' -> 'splitter_processor' ->> 'version') || 
    '", processor: "' || (meta -> 'metadata' -> 'morphology_processor' ->> 'version') || '"' ver
    , meta -> 'metadata' -> 'splitter' ->> 'text' sent
    , jsonb_pretty(sentences.sentence) cont
    FROM sentences 
ORDER BY id DESC LIMIT 1) 

UNION ALL
(SELECT 'syntax' base, substring(meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' FOR 8) process, id, substring(hash::text for 5) hash
    , 'syntax: "' || (meta -> 'metadata' -> 'syntax_processor' ->> 'version') || 
    '", weighting: "' || (meta -> 'metadata' -> 'weighting_processor' ->> 'version') || '"' ver
    , meta -> 'metadata' -> 'splitter' ->> 'text' sent 
    , jsonb_pretty(syntax.tree) cont
    FROM syntax
ORDER BY id DESC LIMIT 1) 

UNION ALL
(SELECT 'facts' base, substring(meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' FOR 8) process, id, substring(hash::text for 5) hash
    , 'syntax: "' || (meta -> 'metadata' -> 'syntax_processor' ->> 'version') || 
    '", weighting: "' || (meta -> 'metadata' -> 'weighting_processor' ->> 'version') || 
    '", semantics: "' || (meta -> 'metadata' -> 'semantics_processor' ->> 'version') || '"' ver
    , F.meta -> 'metadata' -> 'splitter' ->> 'text' sent
    , '' cont
    FROM facts F
ORDER BY id DESC LIMIT 1)

UNION ALL
(SELECT 'fact_valencies' base, substring(meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' FOR 8) process, FV.id, substring(hash::text for 5) hash
    , '' ver
    , F.meta -> 'metadata' -> 'splitter' ->> 'text' sent
    , '' cont
    FROM fact_valencies FV
LEFT JOIN facts F ON FV.fact = F.id 
ORDER BY FV.id DESC LIMIT 1)

UNION ALL
(SELECT 'referents' base, substring(meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' FOR 8) process, R.id, substring(hash::text for 5) hash
    , '' ver
    , F.meta -> 'metadata' -> 'splitter' ->> 'text' sent
    , '' cont    
    FROM referents R
LEFT JOIN fact_valencies FV ON R.id = FV.referent
LEFT JOIN facts F ON FV.fact = F.id 
ORDER BY R.id DESC LIMIT 1)

UNION ALL
(SELECT 'fact_markers' base, substring(meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' FOR 8) process, FM.id, substring(hash::text for 5) hash
    , '' ver
    , F.meta -> 'metadata' -> 'splitter' ->> 'text' sent
    , '' cont 
    FROM fact_markers FM
LEFT JOIN fact_valencies FV ON FM.valency = FV.id
LEFT JOIN facts F ON FV.fact = F.id 
ORDER BY FM.id DESC LIMIT 1)

Возможный результат:

base process id hash ver sent cont
sentences 51f949d3 2343548 2EE67 matcher: “1.3-ak”, guesser: “1.0:WEB”, splitter: “1.2”, processor: “1.0:1.03-lz” осуществление проекта будет разбито на два этапа. { “tokens”: [ { “order”: 1,…
syntax 4e742066 267514 FD4FF syntax: “1.6-D30:1.8 ak”, weighting: “2.3-R0,0100T512:0.5:ak” средняя скорость движения трамваев на маршруте составит более 25 километров в час. { “nodes”: [ { “order”: 1,…
facts 51f949d3 4860251 12D84 syntax: “1.6-D30:1.8 ak”, weighting: “2.3-R0,0100T512:0.5:ak”, semantics: “1.0:1.02-AK” осуществление проекта будет разбито на два этапа.  
fact_valencies 51f949d3 8332498 12D84   осуществление проекта будет разбито на два этапа.  
referents 51f949d3 8332498 12D84   осуществление проекта будет разбито на два этапа.  
fact_markers 51f949d3 20685475 12D84   осуществление проекта будет разбито на два этапа.  

Здесь для каждой таблицы (sentences, synatx и т. д.) видно, какой процесс (например, 51f949d3) добавил запись с каким идентификатором (например, 2343548), на каких версиях компонентов был произведён разбор (matcher: “1.3-ak”, guesser: “1.0:WEB”…), какое предложение разбиралось (осуществление проекта будет…), как выглядит запись предложения, разделённого на словоформы, и как выглядит синтаксическое дерево в формате treeJSON ({ “nodes”: [ { “nodes”: [ { …)

Предложения из последнего разбора

Чтобы просмотреть предложения, которые были проанализированы в рамках последнего запуска, можно использовать следующий запрос:

SELECT N1.*, B.unknown_token FROM
    (
        SELECT     
           substring(A.procid FOR 8) -- преобразуем json в строку и обрезаем
           , Se.id sentID
           , Se.meta ->'metadata'->'splitter'->>'text' sent
           , COUNT(Sy.id) treeCNT
           , COUNT(F.id) fCNT
           -- проверяем, что для предложения сохранено дерево или факт, значит, предложение разобрано
           , CASE (COUNT(Sy.id) > 0) OR (COUNT(F.id) > 0) WHEN True THEN 1 ELSE NULL END oksent

           FROM 
           (    SELECT meta -> 'metadata' -> 'splitter_processor' ->> 'process_id' procid, MAX(id) maxid
                FROM sentences
                GROUP BY procid
                ORDER BY maxid DESC
                LIMIT 1 -- взять последний разбор
           ) A --берем последний procid
           JOIN sentences Se ON A.procid = Se.meta ->'metadata'->'splitter_processor'->>'process_id' 
           LEFT JOIN facts F ON F.meta ->'metadata'->'morphology'->>'id' = Se.meta ->'metadata'->'morphology'->>'id'
           LEFT JOIN syntax Sy ON Sy.meta ->'metadata'->'morphology'->>'id' = Se.meta ->'metadata'->'morphology'->>'id'           

           GROUP BY 
               A.procid
               , Se.id
           ORDER BY --oksent, 
           sentid DESC

       ) N1

      LEFT JOIN

       (
            select X.token->'token'->>'token_text' unknown_token, X.sentID 
                from (
                    select jsonb_array_elements(sentence -> 'tokens') token, id sentID from sentences
                ) X
            where X.token->'token'->>'token_type' = 'Unknown'
       ) B ON B.sentID = N1.sentID
ORDER BY N1.sentID DESC

Возможный результат:

substring sentid sent treecnt fcnt oksent unknown_token
51f949d3 2343552 средняя скорость движения трамваев на маршруте составит более 25 километров в час. 0 4 1 [NULL]
51f949d3 2343551 предполагается, что первая часть маршрута будет закончена к 2023 году. 0 4 1 [NULL]
51f949d3 2343550 на втором этапе будут выстроены 14 километров путей от петергофского шоссе до города петергофа. 0 0 [NULL] [NULL]
51f949d3 2343549 сначала будет построена ветка протяженностью шесть километров от существующих трамвайных путей— по улицам маршала казакова, маршала захарова, балтийскому бульвару, проспекту героев до петергофского шоссе. 0 0 [NULL] [NULL]

Таблица показывает, что в рамках процесса 51f949d3 были проанализированы несколько предложений. Для некоторых из них были успешно пострены факты (fcnt), это значит, что предложение было разобрано. Если в процессе разбора были найдены незнакомые слова, они появятся в столбце unknown_token. Но при использовании компонента «гессер» неизвестных слов не остаётся, для любого слова предлагается та или иная гипотеза разбора.

Теперь можно переходить к анализу результатов разбора в базе данных