Semantic Enrichment Component

Semantic Enrichment Component (zkráceně SEC) poskytuje služby pro sémantické obohacení textu. Poskytuje např. službu anotace textu annotate, hledání entit get_entities a výpis 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).

Obsah

Prerekvizity

Aktuální verze nástroje je dostupná na gitu ve větvi D114-SEC_API.

 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)!

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.

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.

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ěží.

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.

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".

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ěď.

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.

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ří:

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í.

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.

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

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"

kde:

  • <attribute_type> - vychází z XSD, může ale obsahovat i jiné typy, o kterých nevím, kde jsou popsány (např. typ "AnnotationLink")
  • V případě, že <data_type> je:

    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).

    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.

    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
    

    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ří:

    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ů.

    Poskytované služby

    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í 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.

    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
         }
     }
    

    Formát odpovědi

     {
         "annotation": str
     }
    

    Výstupní formáty

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

    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"?>
    <!-- Vygenerováno pomocí: 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>
    
    XML
    HTML
    Text
    Index
    Index2
    RDF
    NIF

    Služba 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.

    Formát požadavku

     {
         "annotate_vertical": {
             "input_text": str,
             "annotation_format": str,
             "vert_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
         }
     }
    

    Formát odpovědi

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

    Služba deverticalize

    Devertikalizuje text ve vertikálním formátu (viz http://www.sketchengine.co.uk/documentation/wiki/SkE/PrepareText nebo http://nlp.fi.muni.cz/cs/PopisVertikalu).

    Formát požadavku

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

    Formát odpovědi

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

    Chyby

    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.

    Formát požadavku

     {
         "get_enrichment_engines": {}
     }
    

    Formát odpovědi

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

    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.

    Formát požadavku

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

    Formát odpovědi

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

    Služba get_entity_by_uri

    Vyhledání entity podle URI.

    Formát požadavku

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

    Formát odpovědi

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

    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.

    Formát požadavku

     {
         "get_entity_types_and_attributes": {}
     }
    

    Formát odpovědi

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

    Služba get_kb_version

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

    Formát požadavku

     {
         "get_kb_version": {}
     }
    

    Formát odpovědi

     {
         "version": int
     }
    

    Služba get_raw_annotations

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

    Formát požadavku

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

    Formát odpovědi

     {
         "annotation": str
     }
    

    Některé generované atributy k typům

    "confidence"

    "identifier"

    "disambiguation"

    <disambiguation> ::= <text v URI mezi závorkami> "," <description> "(" <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í>
    

    Odkazy

    Související články

    Manatee

    Externí odkazy

    Vertikál

    Manatee

    MG4J