Import z plików SQLite (import_sqlite)¶
Aplikacja import_sqlite importuje dane z lokalnych plików SQLite
wyprodukowanych przez zewnętrzne harvestery (narzędzia, które zbierają
rekordy z portali bibliograficznych i zapisują je offline). Pierwszy i obecnie
jedyny obsługiwany typ rekordu to patenty.
Aplikacja mieszka w repozytorium (src/import_sqlite/), nie ma własnych modeli
i nie tworzy migracji — całą pracę wykonują dwa polecenia zarządzania plus
edytowalne pliki CSV, w których człowiek podejmuje decyzje o dopasowaniu
twórców.
Format wejściowy¶
Harvester zapisuje rekordy do tabeli records w pliku SQLite. Import czyta
z niej trzy kolumny:
| kolumna | znaczenie |
|---|---|
type |
rodzaj rekordu (np. patent) — import filtruje po nim |
source_id |
stabilny identyfikator rekordu po stronie źródła |
source_url |
adres strony szczegółów rekordu |
parsed_json |
wyekstrahowane pola rekordu jako JSON |
Warstwa czytająca (reader.py) jest generyczna — filtruje wyłącznie po
kolumnie type. Mapowanie parsed_json na konkretny model BPP robi handler
danego typu (handlers/patent.py). Rekordy z pustym lub niepoprawnym
parsed_json są pomijane z ostrzeżeniem, bez przerywania importu.
Dwie fazy: scan → (ręczne uzgodnienie) → apply¶
Import jest celowo dwufazowy. Faza scan niczego nie zapisuje do bazy — tylko
proponuje dopasowania twórców i wypisuje je do CSV. Człowiek przegląda i
zatwierdza, a dopiero apply tworzy rekordy.
# Faza 1 — skan: czyta SQLite, dopasowuje twórców, wypisuje CSV-e
uv run python src/manage.py import_sqlite_scan \
/sciezka/do/pliku.sqlite3 --typ patent \
--out-autorzy autorzy_do_uzgodnienia.csv \
--out-patenty patenty_do_przegladu.csv
# ← edytujesz autorzy_do_uzgodnienia.csv (wypełniasz kolumnę `decyzja`)
# Faza 2 — podgląd bez zapisu (transakcja wycofywana na końcu)
uv run python src/manage.py import_sqlite_apply \
/sciezka/do/pliku.sqlite3 --typ patent \
--autorzy autorzy_do_uzgodnienia.csv --dry-run
# Faza 2 — właściwy import (bez --dry-run)
uv run python src/manage.py import_sqlite_apply \
/sciezka/do/pliku.sqlite3 --typ patent \
--autorzy autorzy_do_uzgodnienia.csv
Oba polecenia są idempotentne i wznawialne: po uzupełnieniu braków w
CSV kolejny apply doimportowuje resztę, a rekordy już istniejące
aktualizuje zamiast duplikować.
Dopasowanie twórców (rdzeń narzędzia)¶
Twórcy w źródle to zwykłe napisy "Imię Nazwisko". Zamiast dopasowywać każde
wystąpienie z osobna, scan zbiera zbiór unikalnych napisów nazwisk ze
wszystkich rekordów i dopasowuje każdy z nich raz, reużywając komparatora
autorów BPP (crossref_bpp.Komparator). Jedna Twoja decyzja rozprowadza się
potem na wszystkie rekordy zawierające ten napis.
Wynik trafia do autorzy_do_uzgodnienia.csv — jeden wiersz na unikalny napis:
| kolumna | znaczenie |
|---|---|
nazwisko_zrodlowe |
oryginalny napis z pola twórców (klucz wiersza) |
given, family |
wynik podziału napisu na imię i nazwisko |
wystapien |
w ilu rekordach ten napis występuje |
status |
jakość dopasowania (niżej) |
kandydat_1..3 |
najlepsi kandydaci: Nazwisko Imię (#pk, pewność, N publ.) |
decyzja |
wypełnia człowiek |
Statusy dopasowania:
- DOKLADNE — jednoznaczne trafienie; kolumna
decyzjajest wstępnie wypełniona identyfikatorem (pk) dopasowanego autora. Zwykle nie ruszasz. - LUZNE / WYMAGA_INGERENCJI — jest kandydat (lub kilku), ale
potwierdzenie należy do Ciebie;
decyzjastartuje pusta. - BRAK — brak dopasowania; decydujesz Ty.
Semantyka kolumny decyzja:
- pk autora (liczba, np.
441) → przypisz ten napis do istniejącego autora; NOWY→ utwórz nowego autora (imię/nazwisko z podziału napisu), przypisanego do „obcej jednostki" uczelni, bez afiliacji;- puste → napis nierozstrzygnięty (rekord z takim twórcą zostanie wstrzymany, patrz niżej).
Spójne dopasowanie mimo literówek¶
Plik autorzy_do_uzgodnienia.csv jest posortowany po znormalizowanym
nazwisku (bez diakrytyków, ł→l, bez wielkości liter). Dzięki temu różne
pisownie tego samego człowieka (np. Kowalski Jan i Kovalski Jan) lądują
obok siebie — widzisz rozjazd i możesz skierować obie decyzje na ten sam
pk. Dwie pisownie zlewają się wtedy w jednego autora, spójnie we wszystkich
rekordach.
Co powstaje w bazie (patenty)¶
Handler patentów tworzy rekord Patent i powiązania Patent_Autor. Mapowanie
najważniejszych pól:
| Pole BPP | Źródło |
|---|---|
tytul_oryginalny |
tytuł rekordu (przepuszczony przez sanityzację HTML) |
rok |
rok z daty zgłoszenia, a gdy brak — rok z daty udzielenia |
numer_zgloszenia |
numer zgłoszenia (może być pusty) |
data_zgloszenia |
data zgłoszenia |
numer_prawa_wylacznego |
numer prawa/patentu — klucz idempotencji |
data_decyzji |
data udzielenia prawa |
wydzial |
jednostka pierwszego dopasowanego twórcy będącego pracownikiem uczelni |
www |
adres źródła (nośnik proweniencji) |
informacja_z |
słownikowy wpis „źródło importu" (audyt) |
szczegoly / adnotacje |
tytuł obcojęzyczny, klasyfikacje, opisy |
twórcy → Patent_Autor |
w kolejności ze źródła, z zachowaniem oryginalnego napisu jako „zapisany jako" |
Afiliacja twórcy zależy wyłącznie od tego, czy jego jednostka skupia pracowników uczelni (twórcy z „obcej jednostki" są nieafiliowani).
Idempotencja i aktualizacja¶
Kluczem ponownego uruchomienia jest numer_prawa_wylacznego:
- brak takiego rekordu → tworzony jest nowy patent;
- jeden istniejący → aktualizacja (pola skalarne nadpisywane danymi ze źródła; powiązania twórców odtwarzane od nowa — import jest źródłem prawdy dla tych rekordów);
- więcej niż jeden → rekord wstrzymany („niejednoznaczny klucz"), bez zgadywania.
Rekordy wstrzymane¶
Rekord jest wstrzymywany (pomijany, z powodem wypisanym w
patenty_do_przegladu.csv) i zaimportuje się przy kolejnym apply po naprawie,
gdy:
- którykolwiek twórca ma pustą
decyzja(nierozstrzygnięty); - utworzenie powiązania twórcy narusza reguły walidacji (np. wymóg afiliacji);
- klucz idempotencji trafia w więcej niż jeden istniejący rekord.
Cały apply biegnie w jednej transakcji, a każdy rekord w osobnym
savepoincie — wstrzymanie jednego nie cofa reszty. --dry-run wykonuje pełne
przetworzenie i na końcu wycofuje całą transakcję, więc możesz obejrzeć
wynik (statusy w patenty_do_przegladu.csv) bez zapisu do bazy.
Wymagania uruchomieniowe¶
- Komparator autorów odpytuje bazę (dopasowania po tabeli autorów), więc oba
polecenia wymagają żywej bazy BPP. Lokalnie najprościej przez
run-site(ewentualnie z wczytanym zrzutem prawdziwej bazy), a dla właściwego importu — baza docelowa. - Uczelnia musi mieć ustawioną „obcą jednostkę" (używaną dla twórców spoza
uczelni oraz dla nowo tworzonych autorów) — inaczej
applypada czytelnym komunikatem na starcie, zamiast błędem w środku importu.
Rozszerzanie o kolejne typy¶
Warstwa czytająca SQLite jest niezależna od typu. Aby dołożyć obsługę nowego
rodzaju rekordu (np. innego niż patent), dopisz handler w handlers/
(parsowanie parsed_json → obiekt danych + materializacja do modelu BPP) i
podłącz go pod polecenia. Obecnie zaimplementowany jest wyłącznie typ patent.
Struktura kodu¶
src/import_sqlite/
reader.py # generyczny czytnik tabeli `records`
core/author_names.py # podział i normalizacja napisów nazwisk
core/author_matching.py # dopasowanie (Komparator) + agregacja unikalnych
review_io.py # zapis/odczyt plików CSV przeglądu
handlers/patent.py # parsowanie patentu + materializacja do BPP
management/commands/
import_sqlite_scan.py # faza 1
import_sqlite_apply.py # faza 2
Projekt techniczny i plan implementacji: docs/superpowers/specs/ oraz
docs/superpowers/plans/ (pliki *import-sqlite*).