コンテンツにスキップ

エンティティ抽出器

ページやチャンクの中の名前を見つけ、それがどこにあるかを述べる抽出器を追加します。

エンティティ抽出器はテキストの中の名前を見つけ、それがどこにあるかを述べます。ラベル — personorganizationlocationdatemoneyinvoice_number — からスパンへの写像で、各スパンは表層のテキスト、文字範囲、信頼度を持ちます。これは分類器の格子のもう半分です。分類器はテキストが何であるかを述べ、抽出器はその中で何が名指しされているかを述べます。単位ごとに 2 つあります。PageEntityExtractorChunkEntityExtractor です。文書のものは意図的にありません。ページがすでに隙間なく文書を敷き詰めているからです。パッケージ化とインストールは概要の手順に従います。

import re
from collections.abc import Mapping
from typing import Any
from indx_interfaces import (
CapabilityDescriptor,
CapabilityId,
Device,
EntitySpan,
ExtractorId,
PageEntityExtractor,
)
INVOICE_NUMBER = re.compile(r"\b(?:INV|請求)[-‐]?\d{4,}\b")
class InvoiceNumberExtractor:
# What a request names in `extraction.page_ids`. IDs are one namespace
# across all five classifier and extractor ports.
id = ExtractorId("acme-invoice-number")
device = Device.CPU
def extract(self, text: str) -> Mapping[str, tuple[EntitySpan, ...]]:
# Offsets are characters into the text you were handed, counted from
# its first character -- which is this block's own `text`.
found = tuple(
EntitySpan(
text=match.group(),
start=match.start(),
end=match.end(),
confidence=0.95,
)
for match in INVOICE_NUMBER.finditer(text)
)
# A label with nothing found is left out, not returned empty.
return {"invoice_number": found} if found else {}
class Provider:
def descriptors(self) -> tuple[CapabilityDescriptor, ...]:
# This distribution annotates what other capabilities read; it reads nothing.
return ()
def create(self, capability_id: CapabilityId) -> Any:
raise ValueError(f"this provider declares no capabilities, so not {capability_id}")
def page_entity_extractors(self) -> tuple[PageEntityExtractor, ...]:
return (InvoiceNumberExtractor(),)

スパンは、それを名指しするブロックの text を指します。 あなたのモデルが切った窓ではなく、文書全体の連結でもなく、バイトでもなく、文字で、1 つのブロック自身の text フィールドを指します。それはレスポンスがすでに運んでいるものなので、呼び出し側はすでに持っているデータであなたのスパンを解決できます。バイトではなく文字であることは効いています。UTF-8 の日本語では両者が 3 倍違うからです。エンジンにトークン窓があるなら、入力を自分でスライスし、入力の座標でスパンを返してください。あなたの窓については正しく入力については誤っているオフセットは、下流の何も検出できません。

呼び出し側は encode{"extraction": {"page_ids": ["acme-invoice-number"]}} であなたのものを有効にします。インストール済みの ID は機能スナップショットのコンテンツハッシュの外に公表されるので、あなたのものをインストールしても計画は動きません。raise は「自分のもので、壊れている」を意味します。エグゼキューターはログに残し、その単位を飛ばし、実行がすでに対価を払ったエンコードを失敗させるのではなく次の抽出器に尋ねます。devicecost_usd は分類器とまったく同じく既定値付きでクラスから読まれます。ホスト型モデルには Device.EXTERNAL を宣言してください。data_residency を運ぶリクエストは、黙ってテキストを箱の外へ送るのではなく、ソースの取得前に拒否されます。

chunk_entity_extractors() から宣言し、リクエストはあなたの ID を extraction.chunk_ids で名指しします。他はすべて同一です。帰結が 2 つ。チャンク粒度が必要ですCHUNK を求めていないリクエストでチャンク抽出器を名指しすることは取得前の 422 です — そしてページごとではなくチャンクごとに呼ばれるので、1 回の呼び出しに対価がかかるモデルは、はるかに多くの対価を要します。

エグゼキューターがあなたの回答をどうするか

Section titled “エグゼキューターがあなたの回答をどうするか”

すべてのスパンは文書ブロックの metadataentities として、それが見つかったブロック ID で引ける形で書かれます — ページブロックもチャンクブロックも同じです。チャンクブロック自身は不活性のままです。ブロックごとのスパンと並んで、エグゼキューターは集約を書きます。(ラベル, NFKC 正規化した表層形) ごとの数と、残された生の表層形です。

数は同一性ではありません。 共参照解析はスコープ外なので、「山田太郎」と「山田」は 2 つの項目であり、それが同一人物だとは誰も主張しません。正規化は「ABC株式会社」と “ABC株式会社” を統合し、そこで止まります。

entities は予約されています。EncodeRequest に渡した呼び出し側は、上書きされるのではなく拒否されます。

  • 渡されたテキストを、その最初の文字から数えて指すスパンを返す。
  • 空のタプルを返すくらいならラベルを省き、1 つのラベルについて重なるスパンを返さない。
  • 弁護できる信頼度を報告し、較正済みだと主張しない。ベンチマークには較正の相手になる正解がありません。
  • 動けないときは何も公表しない。エクストラなし、辞書なし、モデルなしなら、raise する抽出器ではなく抽出器なし。
  • モジュールスコープを安価に保つ。エンジンのインポートは extract() の内側に、辞書やモデルは最初の呼び出しの背後に置く。