Semantic Enrichment Component


Semantic Enrichment Component (zkráceně SEC) poskytuje služby pro sémantické obohacení textu. Využívá se např. v systému 4A. Poskytuje např. službu anotace textu annotate, hledání entit get_entities a výpisu všech typů a atributů v KB get_entity_types_and_attributes.

Veřejně je služba dostupná na http://sec.fit.vutbr.cz/ na portu 8082 (dokumentace k protokolu). Pro naše účely máme SEC API na všech serverech ve /var/secapi a běží na portu 8082.

Obsah

1 Prerequisities

Aktuální verze nástroje je dostupná na gitu ve větvi D114-SEC_API (username je potřebné změnit za váš login).

 git clone http://sec.fit.vutbr.cz/sec/secapi.git secapi && cd secapi
 git checkout -b D114-SEC_API origin/D114-SEC_API
        

Vytvoří se adresář secapi, do kterého se přesuneme. V adresáři ./NER stáhneme KB a poté v adresáři ./SEC_API sestavíme potřebné programy pomocí příkazu make.

 cd ./NER && ./deleteKB.sh && ./downloadKB.sh)
 cd ./SEC_API && make)
        

Je potřeba si dát pozor na to, aby se při použití skriptu downloadKB.sh nenacházely v adresářích secapi/NER a secapi/NER/figa KB a automaty (*.fsa). Je proto vhodné je ještě předtím smazat pomocí skriptu deleteKB.sh. Pozor, skripty downloadKB.sh a deleteKB.sh se musí spouštět pouze z adresáře ve kterém jsou (tedy ./NER)!


2 Popis částí

SEC naleznete v adresáři ./SEC_API (odtud berme jako pracovní cestu — budou od něj odvozeny relativní cesty). Jeho skripty jsou napsány tak, aby mohly být volány z libovolného adresáře. Aktuálně je SEC rozdělen do skriptů sec_daemon.py, sec.py a sec_api.py.

2.1 Skript sec_daemon.py

Skript sec_daemon.py je jádro celého SEC. Vznikl pro redukci paměťové náročnosti při paralelním běhu sec.py. Jeho spuštěním je vytvořen Unix domain socket (UDS) na kterém čeká na připojení několika instancí skriptů sec.py nebo sec_api.py. Instance těchto dvou skriptů se s sec_daemon.py dorozumívají pomocí vnitřního komunikačního protokolu popsaného dále.

2.1.1 Použití

 ./sec_daemon.py [-h] [-p PATH] [--own_kb_daemon]
  Nepovinné argumenty:
   -h, --help            Ukáže nápovědu a skončí.
   -p PATH, --uds_path PATH
                         Nastaví cestu k Unix domain socketu, kde daemon čeká
                         na klienty. Výchozí hodnota je ./daemon_uds relativně
                         k adresáři skriptu.
   --own_kb_daemon       Spustí vlastní KB daemon i když jiný již běží.
        

2.2 Skript sec.py

Skript sec.py je klient démonu sec_daemon.py. Přes něj jsou služby SEC poskytované démonem reprezentovány uživateli. Na standardním vstupu je očekáván požadavek v JSON. Na standardní výstup je předána odpověď. Popis služeb a požadavků i s příklady naleznete prozatím v ./doc/sec_api.pdf po sestavení příkazem make.

2.2.1 Použití

 ./sec.py [-h] [-t [DIRECTORY]] [-p PATH] [-c CONFIG.json] [--plaintext]
          [-f FILENAME]
        
 Nepovinné argumenty:
   -h, --help            Ukáže nápovědu a skončí.
   -t [DIRECTORY], --testing_mode [DIRECTORY]
                         Přepne do testovacího módu, jenž umožní testovat práci
                         se strukturovanými anotacemi, které NER neumí.
                         To znamená, že služba "annotate" hledá v URI dotazu
                         "DOCUMENT_URI" hodnotu klíče "tid" a podle ní hledá
                         v adresáři DIRECTORY soubor s odpovědí na
                         "annotation_format". Pokud je takový soubor nalezen,
                         pak místo výsledků z NERu se vrátí jeho obsah. URI
                         dotaz "DOCUMENT_URI" může mít i klíč "aid". Oproti
                         klíči "tid", obsah souboru, nalezeného podle této
                         hodnoty, výsledek NERu pouze obohatí (připojí se k němu).
                         Výchozí hodnota je ./testing_mode relativně k adresáři
                         skriptu.
   -p PATH, --uds_path PATH
                         Nastaví cestu k Unix domain socketu, kde daemon čeká
                         na klienty. Výchozí hodnota je ./daemon_uds relativně
                         k adresáři skriptu.
   -c CONFIG.json, --config_file CONFIG.json
                         Nastaví službu a její parametry z JSON souboru, místo
                         ze standardního vstupu. V tom případě je očekáván na
                         standardním vstupu pouze text ke zpracování nebo nic.
   --plaintext           Výstup služeb "annotate", "annotate_vertical"
                         a "get_raw_annotations" je v čistém textu. Pokud nastane
                         výjimka, zůstane v JSON.
   -f FILENAME, --filename FILENAME
                         Nastaví filename pro službu "annotate_vertical".
        

2.3 Skript sec_api.py

Skript sec_api.py je velmi podobný skriptu sec.py a proto jeho část využívá. Na rozdíl od něj na standardním vstupu může být požadavků zadáno více na jednu instanci. Po každém požadavku vytiskne na standardní výstup odpověď. Při spuštění vytvoří i server využívající protokol HTTP a čekající na portu 8082. Přes něj může jakýkoli HTTP klient pomocí HTTP požadavku POST poslat SEC požadavek o konkrétní službu a získat odpověď.

2.3.1 Použití

 ./sec_api.py [-h] [-t [DIRECTORY]] [-p PATH] [-n PORT]
 Nepovinné argumenty:
   -h, --help            Ukáže nápovědu a skončí.
   -t [DIRECTORY], --testing_mode [DIRECTORY]
                         Přepne do testovacího módu, jenž umožní testovat práci
                         se strukturovanými anotacemi, které NER neumí.
                         To znamená, že služba "annotate" hledá v URI dotazu
                         "DOCUMENT_URI" hodnotu klíče "tid" a podle ní hledá
                         v adresáři DIRECTORY soubor s odpovědí na
                         "annotation_format". Pokud je takový soubor nalezen,
                         pak místo výsledků z NERu se vrátí jeho obsah. URI
                         dotaz "DOCUMENT_URI" může mít i klíč "aid". Oproti
                         klíči "tid", obsah souboru, nalezeného podle této
                         hodnoty, výsledek NERu pouze obohatí (připojí se k němu).
                         Výchozí hodnota je ./testing_mode relativně k adresáři
                         skriptu.
   -p PATH, --uds_path PATH
                         Nastaví cestu k Unix domain socketu, kde daemon čeká
                         na klienty. Výchozí hodnota je ./daemon_uds relativně
                         k adresáři skriptu.
   -n PORT, --net_port PORT
                         Nastaví port, kde SEC čeká na klienty. Výchozí hodnota
                         je 8082.
        

2.4 Vnitřní komunikační protokol

Vnitřní komunikační protokol je založen na modelu klient-server využívající Unix domain sockety (UDS) ve stream módu.


Mezi jeho stěžejní body patří:

2.4.1 Postup

  1. Server čeká na klienty.
  2. Klient se připojí.
  3. Klient pošle nastavení serveru (adresář k testovacímu módu a JSON s nastavením požadované služby).
  4. Server přijme a potvrdí klientovi.
  5. Klient pošle data ke zpracování serveru (pokud je požadovaná služba nevyžaduje, mohou být o nulové délce).
  6. Server po klientovi, v rámci testovacího módu, může žádat o otevření několika souborů a poslání jejich file descriptoru (tím se také prokáže oprávnění klienta soubor otevřít).
  7. Server pošle klientovi zpracovaná data.
  8. Klient končí spojení nebo pokračuje bodem č. 5, popř. bodem č. 3.

Pokud server zjistí chybné nastavení nebo dojde k chybě při zpracování, pošle klientovi informace o chybě a končí spojení s ním spojení.

2.4.2 Příkazy a struktury paketů

Na příkazy se můžete podívat v souboru daemon_lib.py. Zde pouze uvedu, že mají dynamicky generované dvoumístné číslo Opcode.

Pro příkazy se používají dvě struktury paketů. Pro chyby je to:

  2 bajty        Řetězec      2 bajty
  ------------------------------------
 | Opcode |  Chybová zpráva  |  CRLF  |
  ------------------------------------
        

Pro zbytek (vyjma file descriptoru) je to struktura, která se opakuje dokud není počet bajtů dat roven nule:

  2 bajty    Číslo (desítkové)   2 bajty    N bajtů    2 bajty
  -------------------------------------------------------------
 | Opcode |  Počet bajtů dat N  |  CRLF  |  Raw data  |  CRLF  |
  -------------------------------------------------------------
        

Pro zasílání file descriptorů se používá knihovna python-fdsend.


3 Podpora více NERů

Ve vývoji - dokumentace bude doplněna (nyní pouze stručně to nejnutnější):

 ner_manager.appendNER("default", module_annotate.NER())
        

podobný řádek s jiným jménem NERu a instancí jiného obalu

3.1 Specifikace výstupu z NERů

Specifikace je vytvořena podle našeho NERu a dalších požadavků. U výstupu z NERů se předpokládá syntaxe (BNF):

 <výstup z NERů> ::= <origin_base>
     | <origin_base> "\t" <id>
     | <origin_base> "\t" <id> "\t" <direct_attributes>
 <origin_base> ::= <start_offset> "\t" <end_offset> "\t" <data_type> "\t" <string_between_offsets> "\t" <data>
 <data_type> ::= "kb"
     | "activity"
     | "date"
     | "interval"
     | "coref"
     | "uri"
 <data> ::= <data-kb>
     | <data-activity>
     | <data-date>
     | <data-interval>
     | <data-coref>
     | <data-uri>
 <data-kb> ::= <KB_row> | <KB_row> ";" <data-kb>
 <data-date> ::= <year> "-" <month> "-" <day>
 <data-interval> ::= <data-date> " -- " <data-date>
 <data-coref> ::= <data-kb>
 
 <direct_attributes> ::= <attribute> | <attribute> "|" <direct_attributes>
 <attribute> ::= <attribute_name> "[" <attribute_type> "]=" <attribute_value>
 <attribute_type> ::= "string" | "decimal" | "date" | "image" | "integer" | "uri" | <other_attribute_type> 
 
 <year> ::= <digit> <digit> <digit> <digit>
 <month> ::= <digit> <digit>
 <day> ::= <digit> <digit>
 <digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
        

where:


4 Volání SEC jako knihovny

Za účelem, aby při použití v SEC jiným programem nebylo potřeba vytvářet subproces se sec.py, byla vytvořena třída Sec v sec.py. Její metody jsou popsány přímo ve zdrojovém kódu. Stejně jako u sec.py je nutné mít spuštěný sec_daemon.py a inicializovat tuto třídu s cestou k Unix domain socketu, kde daemon čeká. Konfigurace se zadávají podobně jako pro sec.py s tím rozdílem, že místo JSONu se používá alternativa Pythonu (viz tabulka).


5 Spuštění na gridu

Pro spouštění SEC na gridu (SGE) byl vytvořen skript ./sge/sec.sh.

Byly na něj kladeny tyto požadavky:

Výsledný ./sge/sec.sh přijímá stejné argumenty jako sec.py. I když byl dělán pro spouštění na gridu, je možné jej využít i na obyčejných strojích (což je možná zřejmé, ale radši to tu píšu).

V rámci tohoto cíle byl vytvořen přepínač --own_kb_daemon u sec_daemon.py a --plaintext u sec.py. K tomu bylo v KB démonu umožněno měnit název sdílené paměti argumentem programu.

5.1 Využití na způsob NERu

Pro použití SEC se stdin/stdout NERu stačí využít služby "get_raw_annotations". Je k tomu třeba vytvořit si konfigurační soubor (např. "get_raw_annotations.cfg"), např. s:

 {
     "get_raw_annotations": {}
 }
        

Poté může být NER volán přes SEC takto:

 ./sge/sec.sh -c get_raw_annotations.cfg --plaintext
        

6 Spuštění na Salomonu

Pro běh na superpočítači Salomon (IT4I) byly vytvořeny skripty nacházející se ve složce ./salomon.

SEC je závislý na několika knihovnách, které na Salomonu nejsou nainstalované. Proto je nutné je nakopírovat z knot09:/mnt/minerva1/nlp/projects/corpproc/dependencies_for_salomon/opt. Lze to provést např. tímto postupem:

 $ mkdir -p ~/mnt/ssh-knot-knot09
 $ sshfs xlogin01@knot09.fit.vutbr.cz:/ ~/mnt/ssh-knot-knot09/
 $ cp -r ~/mnt/ssh-knot-knot09/mnt/minerva1/nlp/projects/corpproc/dependencies_for_salomon/opt ~/
 $ fusermount -u ~/mnt/ssh-knot-knot09
        

Závislosti již jsou sestavené. Pokud by byla potřebná nová kompilace, stačí spustit ./salomon/prepare.sh.

Ke spuštění slouží skript ./salomon/start.sh, jenž je v několika variantách. Každá z těchto variant očekává:

 $ ls ~/parsed | sed 's/\.vert.*//g' > ~/namelist
        

po spuštění vytvoří:

6.1 Varianty

  1. Varianta ./salomon/start.sh spustí na jednom uzlu pro každý soubor z ~/namelist zvlášť instanci ./sge/sec.sh.
  2. Varianta ./salomon/v2/start.sh vyžaduje argument definující počet úloh na uzel. Podle něj a podle počtu souborů v ~/namelist vytvoří potřebný počet úloh, jenž obsadí všechny uzly dostupné uživatelem pro jeden job dle limitů.

7 Poskytované služby

7.1 Služba annotate

Tato služba vrací anotace pro zadaný dokument. Využívá k tomu enrichment engine zvolený uživatelem. Anotace obsahují informaci o jejich umístění v dokumentu (počáteční a koncový ofset), délce a samotný anotovaný text. Dále obsahují informace získané z KB mezi nimiž je např. typ, název a URL na wikipedii.

Enrichment engine volí uživatel v parametru enrichment_engine. Dále může zadat i jeho maximální dobu zpracování (v sekundách) parametrem enrichment_engine_timeout. K výpisu všech enrichment engines lze využít službu "get_enrichment_engines".

Text v dokumentu bývá většinou víceznačný a proto enrichment engine může nalézt více možných entit k danému textu. Pokud je nastaven parametr disambiguate, pak enrichment engine vybere ten nejpravděpodobnější význam anotovaného textu.

Formát výstupu této služby lze zvolit parametrem annotation_format. Pro jeden vstup je možné zvolit více formátů výstupu. Pozn.: Toto by možná chtělo upravit tak, aby při "plaintext": false byl výstupem vždy korektní JSON. Parametr "annotation_format" může nabývat těchto hodnot:

Parametrem types_and_attributes lze určit, jaké informace z KB se zahrnou do výstupu. Tedy je možné povolit jednotlivé typy a k nim buď všechny jejich atributy (syntaxe { str(type): "all" }) nebo jen některé (syntaxe { str(type): [ str(attribute), ... ] }). Jeho výchozí hodnotou je "all", což znamená, že je povolen výpis všech typů anotací i všech jejich atributů. Všechny dostupné typy a jejich atributy, lze vypsat pomocí služby "get_entity_types_and_attributes".

Parametr document_uri slouží k zadání URL adresy ze které byl dokument přebrán. Je-li nastaven výstupní formát NIF, pak je tento parametr nutný.

Je-li parametr plaintext nastaven na true, ruší zapouzdření výstupu do JSONu. V tom případě jsou různé výstupní formáty odděleny znakem '\0'.

Ukázky a další informace je možné nalézt zde.

7.1.1 Formát požadavku

 {
     "annotate": {
         "input_text": str,
         "annotation_format": [ str, ... ],
         "disambiguate": int,
         "document_uri": str,
         "types_and_attributes": "all" | { str(type): "all" } | { str(type): [ str(attribute), ... ] },
         "enrichment_engine": str,
         "enrichment_engine_timeout": int,
         "plaintext": bool
     }
 }
        

7.1.2 Formát odpovědi

 {
     "annotation": str
 }
        

7.1.3 Output format

Formát výstupu této služby lze zvolit parametrem annotation_format. Zde tyto formáty popíši podrobněji.

7.1.3.1 SXML

XML dokument obsahující pouze anotovaný text. Je určen převážně pro další zpracování.

 <?xml version="1.0" encoding="UTF-8"?>
 <!-- Generated using: trang -I xml -O rng *.sxml SXML.rng -->
 <grammar ns="" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <start>
    <element name="suggestion">
      <zeroOrMore>
        <element name="text">
          <attribute name="e_offset">
            <data type="integer"/>
          </attribute>
          <attribute name="s_offset">
            <data type="integer"/>
          </attribute>
          <attribute name="string"/>
          <zeroOrMore>
            <element name="annotation">
              <optional>
                <attribute name="id">
                  <data type="anyURI"/>
                </attribute>
              </optional>
              <attribute name="type">
                <data type="NCName"/>
              </attribute>
              <zeroOrMore>
                <element name="attribute">
                  <optional>
                    <attribute name="annotType">
                      <data type="NCName"/>
                    </attribute>
                  </optional>
                  <attribute name="name">
                    <data type="NCName"/>
                  </attribute>
                  <attribute name="type">
                    <data type="NCName"/>
                  </attribute>
                  <text/>
                </element>
              </zeroOrMore>
            </element>
          </zeroOrMore>
        </element>
      </zeroOrMore>
    </element>
  </start>
 </grammar>
        
7.1.3.2 XML
7.1.3.3 HTML
7.1.3.4 Text
7.1.3.5 Index
7.1.3.6 Index2
7.1.3.7 RDF
7.1.3.8 NIF

7.2 Service annotate_vertical

Speciální klon služby "annotate" pro anotaci vertikálu. (Z tohoto důvodu popíši pouze rozdíl.) Její částí je služba "deverticalize", jenž se stará o postupné získání jednotlivých dokumentů ze vstupu ve vertikálním formátu. Formát výstupu musí být určen v požadavku.

7.2.1 Request format

 {
    "annotate_vertical": {
        "input_text": str,
        "annotation_format": str,
        "vert_in_cols": [ str, ... ],
        "vert_out_cols": [ str, ... ],
        "types_and_attributes": "all" | { str(type): "all" } | { str(type): [ str(attribute), ... ] },
        "enrichment_engine": str,
        "enrichment_engine_timeout": int,
        "filename": str,
        "num_workers": int,
        "plaintext": bool,
        "max_values_per_col": int | null,
        "wiki_mode": bool,
        "enable_figa": bool
    }
 }
        

7.2.2 Formát odpovědi

 {
     "annotation": str | [
         {
             "title": str,
             "uri": str,
             "article": str
         },
         ...
     ]
 }
        

V případě, že annotation_format bude "elasticsearch", pak hodnotou klíče annotation bude list objektů, v opačném případě řetězec.

7.3 Služba deverticalize

Devertikalizuje text ve vertikálním formátu (see https://www.sketchengine.co.uk/documentation/preparing-corpus-text/ or http://nlp.fi.muni.cz/cs/PopisVertikalu).

7.3.1 Formát požadavku

 {
     "deverticalize": {
         "input_text": str,
         "vert_in_cols": [ str, ... ]
     }
 }
        

7.3.2 Formát odpovědi

 {
     "deverticalized": [
         {
             "id": str,
             "document": str
         },
         ...
     ]
 }
        

7.3.3 Chyby

7.4 Služba get_enrichment_engines

Vypíše všechny dostupné enrichment engines. Tedy hodnoty jakých může nabývat atribut enrichment_engine, používaný u některých služeb.

7.4.1 Formát požadavku

 {
     "get_enrichment_engines": {}
 }
        

7.4.2 Formát odpovědi

 {
     "enrichment_engines": [ str, ... ]
 }
        

7.5 Služba get_entities

Dle zadaného jména do artibutu input_string vypíše všechny entity z KB, které mají stejné nebo podobné jméno. Výstup je seřazen podle hodnoty atributu entity confidence. Lze filtrovat stejně jako u služby "annotate" pomocí atributu types_and_attributes.

Ukázky a další informace je možné nalézt zde.

7.5.1 Formát požadavku

 {
     "get_entities": {
         "input_string": str,
         "types_and_attributes": "all" | { str(type): "all" } | { str(type): [ str(attribute), ... ] },
         "max_results": int
     }
 }
        

7.5.2 Formát odpovědi

 {
     "data": [
         {
             str(type): {
                 str(attribute): str,
                 ...
             }
         },
         ...
     ]
 }
        

7.6 Služba get_entity_by_uri

Vyhledání entity podle URI.

7.6.1 Formát požadavku

 {
     "get_entity_by_uri": {
         "input_string": str,
         "types_and_attributes": "all" | { str(type): "all" } | { str(type): [ str(attribute), ... ] }
     }
 }
        

7.6.2 Formát odpovědi

 {
     "data": [
         {
             str(type): {
                 str(attribute): str,
                 ...
             }
         },
         ...
     ]
 }
        

7.7 Služba get_entity_types_and_attributes

Vypíše všechny dostupné typy a jejich atributy. Tato informace lze využít u atributu types_and_attributes, který u některých služeb slouží jako filtr.

7.7.1 Formát požadavku

 {
     "get_entity_types_and_attributes": {}
 }
        

7.7.2 Formát odpovědi

 {
     "data": [
         {
             "type": str(type),
             "attributes": [
                 str(attribute),
                 ...
             ]
         },
         ...
     ]
 }
        

7.8 Služba get_kb_version

Vrátí číslo verze načténé KB.

7.8.1 Formát požadavku

 {
     "get_kb_version": {}
 }
        

7.8.2 Formát odpovědi

 {
     "version": int
 }
        

7.9 Služba get_raw_annotations

Vrátí řetězec získaný pomocí NERu.

7.9.1 Request format

 {
     "get_raw_annotations": {
         "input_text": str,
         "disambiguate": int,
         "enrichment_engine": str,
         "enrichment_engine_timeout": int,
         "plaintext": bool
     }
 }
        

7.9.2 Formát odpovědi

 {
     "annotation": str
 }
        

8 Některé generované atributy k typům

"confidence"

"identifier"

"disambiguation"

 <disambiguation> ::= <text v URI mezi závorkami> "," <popis> "(" <interval žití> ")"
                    | <text v URI mezi závorkami> "(" <interval žití> ")"
                    | <text v URI mezi závorkami>
                    | <description> "(" <interval žití> ")"
                    | <description>
                    | <interval žití>
                    | ""

 <interval žití> ::= <YYYY-MM-DD datum narození> -- <YYYY-MM-DD datum úmrtí>
                   | "born " <YYYY-MM-DD datum narození>
        

9 Odkazy

9.1 Související články

9.2 Manatee

9.3 MG4J

9.4 Externí odkazy