Пошук: канали, склейка, поріг¶
Пошук у прочитаному — не grep. Машинний текст скоропису XVIII–XIX ст. має
частку помилок у десятки відсотків, і потрібне прізвище виходить із рушія
спотвореним до невпізнання. Тому шукається схожість нормалізованих токенів,
а не підрядок.
Це документ про пошук у вже прочитаному. Де взяти матеріал, якого в
просторі ще немає, у які джерела йти і в якому порядку — where-to-dig.md.
Три сховища, а не три «канали»¶
search.run має поле where, і це вибір сховища, а не способу пошуку:
where |
що шукає | коли брати |
|---|---|---|
decode (дефолт) |
машинний текст усіх прогонів | шукаємо там, де ще ніхто не дивився |
pages |
прізвища, виписані оком у облік | перевірити, чи не знаходили це раніше |
records |
учасники розібраних записів (батьки, восприємники, свідки) | шукаємо роль, а не згадку |
Роль і тип акту — поля, а не читання очима. У where=records є role
(father, godfather, deceased…) і rtype (birth, death…): «хто був
батьком із цим прізвищем» і «хто був восприємником» — різні питання, і саме
заради них записи розбирають структурою. Фільтр, який не діє в обраному
сховищі, відмовляється, а не мовчить: тихо ширша вибірка виглядає як
звужена, і нуль по ній закриває напрям, якого не перевіряли.
Вісь: прізвище чи місце. axis=place (у pages і records) шукає не по
прізвищу, а по поселенню — «які акти згадують це село, байдуже під яким
прізвищем». Місце тримається двічі: на записі (де відбулась подія) і на
учаснику (звідки він), і в шлюбі це різні села.
nysh records grep "Ковальський" --role father --json
nysh records grep "Городківка" --axis place --json
Шифра — це запит іншого роду¶
catalog.search (nysh find) розрізняє два питання. «Мястківка» — це «де
взагалі є щось про моє село», і відповідь на нього перелік. «127-1078-1662» —
це адреса конкретної справи, і відповідь одна.
Доти на адресу відповідав текстовий пошук, тобто не відповідав ніколи: три числа поспіль не трапляються в жодному заголовку. Нуль давала й «ДАВіО-172-4-112» — рядок, який пошук САМ друкує в кожному хіті як адресу справи, тобто показане не можна було набрати назад.
Адресний маршрут питає інші місця й у такому порядку: бібліотека (справа може вже лежати на цій машині) → реєстр опису (заголовок, роки, аркуші, звідки взяти) → каталоги, які вміють шукати за шифрою.
🔴 Це видно у відповіді, і мусить бути видно: coverage.searched містить рівно
те, що питали, а попередження address_route каже прямо, що повнотекстового
пошуку по каталогах НЕ було. Джерело, яке вміє лише текстом, іде в
unavailable з причиною — його нуль не є нулем про цю справу.
Якщо адреса не знайшлась ніде, запит іде текстом як звичайний: рядок може бути
лише схожий на шифру (дата «1858-03-14»). Примусово текстовий маршрут —
nysh find … --text.
🔴 Нуль у кожному з трьох означає різне. «Немає в decode» — немає в
машинному тексті, який міг це слово скалічити. «Немає в pages» — ніхто не
виписував, і це майже нічого не каже про джерело. «Немає в records» — ніхто
не розбирав записи, навіть якщо прізвище там є.
Тому знаменник у відповіді різний за змістом, і в звіті його треба називати разом зі сховищем, а не окремо.
Де лежить текст: стор¶
Пошук по декоду читає не теки прогонів, а текстовий стор — один файл SQLite
(data/derived/text_store.sqlite) із сирим текстом сторінок, рядками й
рамками, тригамним індексом і готовими кандидатами: склейки через рядок і за
колонкою вже в них. Обхід тек прогонів на великому корпусі коштує хвилини, стор
відповідає за секунди. search.run бере стор сам, щойно той покриває область,
і каже про це в coverage.backend; прогони поза стором ідуть старим шляхом.
nysh text state # скільки прогонів у сторі, скільки застаріло
nysh text index # догнати після нових прогонів
nysh text state --verify # довести однорідність після обірваної перебудови
Стор, який саме пише інша сесія (повна індексація, optimize, наглядач хмари
після справи), text index чекає до 30 хв, а не пропускає: поступ каже
«чекаю стор: пише інша сесія». Прогін, який за цей час проіндексував хтось
інший, удруге не збирається. Лише понад 30 хв прогін лишається поза стором — і
це тривога в locked_skipped, а не примітка.
Де файл і скільки процесів. Стор росте до десятків ГБ, а корпусний пошук
читає його майже цілим. На повільному диску його виносять полем маркера
простору — text_store = "<тека>" у [workspace] файла nyshporka.toml
(nysh text state друкує, звідки читає). Блоки корпусу чешуть три процеси
разом, кожен бере до 1.5 ГБ пам'яті; на слабкій машині —
NYSH_SWEEP_WORKERS=1.
🔴 Відбиток правил склейки, який друкує state, — це заява, а не доказ. Якщо
перебудову обірвано (брак пам'яті, Ctrl+C, закрите вікно), приймач —
--verify: він перераховує кандидатів звірених сторінок чинним кодом і називає
прогони, де вони розійшлись. Код виходу 1 означає, що пошук по цих прогонах
відповідає не тим, чим по решті.
⚡ Швидкий індекс для великих областей¶
Свіп триграмами по всьому корпусу — хвилини на прізвище (на 3 млн сторінок: 4–17 хв трьома воркерами). Необов'язковий індекс Tantivy поруч зі стором знаходить рядки-кандидати за десятки секунд, а бал і далі ставить той самий rapidfuzz із тим самим порогом.
nysh text index --fast # зібрати (години на великому сторі) або догнати
- Ставиться окремо:
pip install nyshporka[fast]. Без пакета чи без індексу все працює свіпом, як раніше. - Береться сам, коли область від ~200 тис. сторінок (корпус, великий фонд). Справа й невелика серія лишаються на свіпі — там він дешевший.
- 🔴 Нуль по області підтверджує свіп. Передфільтр губить частину смуги 90–94; «немає» без свіпу триграмами не друкується.
- Прогін, змінений після збірки індексу (новий штамп чи правила склейки),
іде свіпом, доки
nysh text indexне дожене індекс. Зіпсований індекс — теж свіп, і відповідь каже про це полемfast_error. - Заміряно на корпусі 3 млн сторінок: прізвище з 22 формами — 2,4 хв проти ~17, поширене коротке — 1,7 хв проти 4,2; на голдсеті роду знайдено ті самі справжні згадки, а сторінок на око — у 2,4 раза менше.
👥 Два слова поруч: nysh text near¶
Часто шукають не одне слово, а пару: ім'я з прізвищем, прізвище з селом, ім'я з по батькові, два прізвища одного запису, стан з іменем («однодворецъ» + «Іосифъ»). Окремий запит кожним словом дає дві купи збігів, і звести їх доводиться оком.
nysh text near "Ковальський" "Іван" --case <справа> # той самий рядок або сусідній
nysh text near "Ковальський" "Городківка" --window 3 # по всьому прочитаному
- Довше слово шукається по всій області тим самим свіпом, що й прізвище (на
корпусі — швидким індексом), коротше — лише на рядках ±
--windowбіля нього. Порядок слів у команді не важить. - Обидва слова розгортаються, як у пошуку прізвища: гніздо імен, написання роду з профілю. Розгорнутий двійник коротший за 4 літери («jan» від «Іван») у пару не йде: він сидить усередині будь-якого слова («Стефанъ»). Набране людиною лишається.
- Кандидат, який схожий на перше слово не менше, ніж на друге, другим не рахується: «Іван» усередині «Іваненко» на тому самому місці — не пара.
--window 0— той самий рядок, 1 (типово) — ще й сусідні: перенос і колонки. Слово в кінці рядка стор склеює з початком наступного, тож для нього вікно вниз на рядок ширше.- Нуль — зі знаменником: на скількох рядках і сторінках знайдено перше слово. «Пари немає» при сотні місць першого і при нулі — різні відповіді.
⚠ Межа вікна — рядки, а не запис. Ознаки родини з різних колонок одного запису
зводить канал запису (text find --case), і лише для людей роду з профілю.
Регекс по сирому тексту замість rg — nysh text grep; усі канали пошуку роду
разом, із журналом — nysh text find (див. surface.md).
Що робить пошук по декоду сам¶
Нормалізація обох сторін¶
Запит і текст зводяться до спільної форми: кирилиця й латинка, історичні літери, типові плутанини самого рушія. Тому запит кирилицею знаходить латинський запис і навпаки — а точний підрядок не знайшов би нічого.
🔑 Гніздо написань імені¶
Нормалізація вирівнює письмо, але не знає, що Явдоха — це Євдокія. Тому запит іменем додатково розкривається довідником церковних імен: шукається все гніздо, а не лише набране слово.
Чому це не косметика — заміряно на живому rapidfuzz при порозі 80:
| набрали | у книзі стоїть | бал | знайшлось би без довідника |
|---|---|---|---|
| Явдоха | Євдокія | 61.5 | ні |
| Осип | Іосиф | 66.7 | ні |
| Оксана | Ксенія | 66.7 | ні |
| Семен | Симеон | 72.7 | ні |
| Ганна | Анна | 88.9 | так |
Тобто для більшої частини гнізда це різниця між знахідкою й мовчазним нулем, а не «трохи нижче порога».
⚠ Прізвища так НЕ зводяться. «Гончаръ» і «Ганчаръ» можуть бути різними родами; їх зближує тільки fuzzy, і рішення лишається за оком.
Вимикач — --no-given. Він потрібен рівно для одного: порівняти, що додав
довідник, коли хітів забагато.
🔑 Написання прізвища з профілю¶
Профіль простору знає прізвище десятком написань (відмінки × орфографії), і пошук бере їх усі, коли запит справді про це прізвище. Одне число знаменника замість десятка окремих нулів.
Що це дає, заміряно при порозі 80 на профілі «Сікорський»:
| у книзі стоїть | лише набране | + написання профілю |
|---|---|---|
| корскаго (з'їдено початок) | 58.8 | 85.7 ← інакше не знайдеться ніколи |
| Сикорскаго | 87.5 | 100.0 |
| Сикорского | 87.5 | 100.0 |
Рушій з'їдає початок слова частіше, ніж кінець, і саме такий уламок лишається поза порогом, поки шукають однією формою.
⚠ Чужий запит форми роду за собою не тягне: пошук по назві села лишається пошуком по назві села. У відповіді видно, чиї написання підмішано.
🏠 Рід — будь-який профіль файла, а не лише активний. Файл
config/research_profile.yaml тримає кілька родів (profiles), а fallback
лише каже, який із них — рід самого простору. Запит шукає свій рід серед УСІХ:
«Коваленко» дістає написання профілю Коваленків, навіть коли простір веде інший рід.
Назвати рід явно — --family <ключ профілю>. Від роду беруться написання,
правила рангу (confusers, rank_down), люди-якорі й ознаки запису.
Друга родина заводиться тією самою командою, що й перша, і fallback не
чіпає: nysh profile init <Прізвище> --name <ключ> --paradigm <парадигма>.
Вимкнути — --no-profile.
🔑 Ранг: чуже слово опускає хіт, але не забирає¶
Профіль тримає confusers (сусідні прізвища на той самий хвіст) і rank_down
(іменовані регекси службових формул). Хіт, який чуже слово пояснює краще,
ніж шукане прізвище, падає вниз видачі з названою причиною — і лишається у
видачі.
🔴 Це не фільтр, і різниця тут не косметична. Ціна помилки асиметрична: хибний плюс людина відсіює за секунди, а пропущений аркуш не відсівається нічим, бо його ніколи не буде в списку.
Навіщо взагалі: бал сам по собі не відділяє рід від рутини. Замір приватного конвеєра — 60 сильних кандидатів, з них рубрика книги 26, сусідній рід 19, шуканий рід нуль, і всі три верхні місця за балом займала рубрика.
Вид збігу й бал слова¶
Кожен хіт несе match — як стем ліг на слово, — а відповідь несе розклад
matches за цими видами:
match |
що це | бал |
|---|---|---|
exact |
слово після нормалізації — саме стем | 100 |
variant |
схоже слово тієї ж міри (рушій перекрутив літери) | схожість цілого слова |
ending |
стем — початок довшого слова: інший відмінок чи закінчення (латинський «Ja-» на місці «Я» — теж) | бал вікна, не вище 99 |
inside |
стем усередині довшого слова: злиплі рушієм ім'я й прізвище або чуже прізвище з тим самим хвостом | бал вікна, не вище 99 |
Порядок видачі: клас рангу (вище) → вид збігу (exact, далі variant і
ending разом за балом, далі inside) → бал. 🔴 inside — не відсів і не
«не наш»: злипле «Олександрярошинський» — теж рід. Він лише нижче. Замір
07.10.2026 на «Ярошинський»: із 296 тис. збігів inside — 240 тис., точних 24;
доти бал рахувався по найкращому вікну слова, і «Pan Paroszynskiin» мав ту саму
сотню, що й «Ярошинський». Порівнюючи бали з давніми записами, пам'ятай, що
стара сотня могла бути inside.
⚠ rank_down — регекси, і порівнюються вони з нормалізованим текстом
(щ→sc, ч→c, и/і→i, кирилиця в латинку). Правило, написане кирилицею, не
спрацює ніколи; пошук каже про це вголос, а не мовчить.
⚓ Канал імен: коли прізвища в тексті вже немає¶
--anchors шукає рядки, де ім'я й по батькові роду стоять поруч. Це інший
вхід, а не ширший поріг: рушій калічить довге прізвище сильніше, ніж коротке
формулярне слово, тож у приватному конвеєрі обидва золоті рятунки мали по
прізвищу бал нуль, а по батькові той самий рушій прочитав дослівно.
Заміряний виграш там: прізвищний канал 61-72%, разом із якорями 85-91% (знаменники різні — 97, 75 і 73 аркуші, і число без знаменника не переносьте).
Три правила, кожне куплене заміром:
- пара обов'язкова. Одиночне «Іосифовъ» стоїть у метриці на кожному аркуші; канал, який приймає одинака, знаходить усе, тобто нічого;
- вікно років, і воно РІЗНЕ. Ім'я корисне, поки людина жива; по батькові —
поки живі її діти (
нар+18 … нар+100), тобто воно переживає носія на покоління. Без прив'язки до років якір вироджувався до чверті рядків книги; - без дати особа якір не звужує і за замовчуванням у нього не йде — але про це сказано числом, а не мовчки.
Якорі беруться з поля kin профілю роду, а канон осіб їх доповнює
(canon.md) — лише для роду самого простору (fallback): люди канону
іншій родині не родичі, і їхні імена в її якорях знаходили б наш рід під
виглядом чужого. Порожній канон звужує канал до kin. Канал без kin і без
канону мовчить — це не нуль.
Формат kin — перелік людей роду під профілем:
profiles:
kovalenko:
surname: {display: Коваленко, paradigm: noun_ko, stems: {uk: Коваленк, ru_prereform: Коваленк}}
kin:
- {given: Тимофій, patronymic: Митрофанов, born: 1847, died: 1923}
- {given: Фекла, patronymic: Харитонова, born: 1851}
- {given: Ганна, patronymic: Степанова, surname: Мельник, born: 1872}
born/died — роки; без жодного людина в якорі не йде (вікно не звужує).
surname — прізвище людини, коли воно не прізвище роду (дівоче в дружини):
каналу запису це ще одна ознака. Рік пишіть із запису, звіреного оком, а не з
пам'яті родини: вікно, зсунуте на покоління, мовчки вимикає людину.
⚠ Працює в межах справи: вікно береться з її років. Поза справою операція відмовляється, а не шукає наосліп.
🏠 Канал запису: родина з різних колонок одного запису¶
--record (у text find — завжди в межах справи) зводить ознаки родини
— прізвище роду, ім'я, по батькові, прізвище людини з kin — у межах
одного запису, а не рядка. Метрика, сповідка, ревізія — таблиці: ім'я
дитини в одній колонці, батьки в другій, кума в третій, і рушій читає їх
окремими рядками. Прізвищний канал і канал імен дивляться на рядок, тож
запис, де прізвище батька скалічене, для них не існує.
Заміряно на метриках одного села й парафій навколо (47 книг, родина з 13 людей
kin, 17 записів, звірених оком):
| прізвищний канал | канал запису | |
|---|---|---|
| народження 1870-х, де батька (ім'я, по батькові, прізвище) рушій скалічив до невпізнання | серед 4475 збігів книги — немає | 1-ше місце зі 131 запису книги |
| знайдено звірених записів | — | 16 із 17: 6 — першими у своїй книзі, 12 — у першій шістці |
Що втрачено, названо: запис польською 1923 р., де ім'я розірване переносом («Pro- / kopij»), а латинський голос не має геометрії — дві ознаки на сторінці без меж запису кандидатом не стають (нижче).
Правила, кожне куплене заміром:
- межа — запис, а не сторінка. Запис — смуга шести медіанних рядків у геометрії сторінки, через усі колонки й обидві половини розвороту. На сторінці чотири-вісім записів, і зведене по сторінці з'єднує чужих людей: ім'я сина з одного запису, по батькові батька з другого, ім'я матері з третього;
- вага ознаки — неймовірність випадкового збігу в самій смузі. Частота
ознаки
f— з книги, на слово; смуга зNслів зустріне її випадково з імовірністю1 − (1 − f)^N, вага —−lnцієї імовірності. Шапка графи й «Марія» в довгій смузі важать майже нуль самі собою, та сама «Марія» в короткому записі метрики — ні; масове в селі прізвище роду просто важить менше. Ручних ваг і стоп-списків немає. Ознаки, які смуга звичайного розміру зустрічає частіше, ніж у половині випадків, відповідь називає; - одне слово — одна ознака. «Митрофаъ» схожий і на ім'я Митрофан, і на по батькові Митрофанов; зарахований двічі, він робив «родину» з одного спотвореного слова;
- по батькові — лише слово у формі по батькові. «Іоаннъ» і є Іван, але це ім'я сусіда, а не «Ивановъ» нашої людини; польське «syn Mitrofana» — форма по батькові;
- голос без геометрії зводиться по сторінці, з позначкою, і там потрібна на одну ознаку більша.
🛑 Межа: щільний поіменний реєстр. Родовідна книга, список, сповідка з сотнями імен на аркуші — не жанр каналу. Там імена стоять гронами, і будь-яка смуга ловить кілька частих імен родини випадково: на ДАХмО 230-1-13 (родовідна книга, ~980 тис. слів, 47 людей канону) контрольний акт роду стоїть 420-м із 3470. Для списку працює блок за абеткою, а не канал запису; число в журналі тут не відповідь «роду немає».
Канал подає запис на око, а не вирішує: двоє людей з однаковими ім'ям і
прізвищем в одному селі — звичайна річ, і розрізняє їх лише повний запис.
Журнал find міряє канал тим самим знаменником ока, що й самоперевірку
(«око 2/2»).
🎯 Самоперевірка: чи бачить пошук те, що око вже знайшло¶
--selfcheck міряє recall на аркушах, де прізвище виписала людина,
дивлячись на скан. Це третє з трьох чисел, без яких нуль не є відповіддю.
- знаменник — позитиви ∩ фактично декодовані сторінки: аркуш, який око знає, а рушій не читав, у знаменник не входить, інакше ми міряли б повноту декоду;
- два числа, не одне: знайдено і подано на око. Розрив між ними — те місце, де вимірювач починає брехати у свій бік;
- позитивів немає → відмова, а не нуль. Порожній recall і нульовий recall означають протилежне.
🧾 Чим справу вже шукали¶
Пошук у межах справи лишає слід: запит, поріг, скільки знайшов, якими моделями. Якщо справу вже прочісували іншим рушієм, наступний пошук каже про це — бо «обшукано» протухає мовчки: та сама справа тим самим запитом дала +8 аркушів роду від самої лише зміни моделі.
🔑 Побутове ім'я — окремий шар, вимкнений¶
Хрестильне ім'я за святцями й побутове, яким людину звали далі, бувають різними іменами: у метриці Васса, у всіх пізніших документах Анна. Це не варіанти написання — це дві різні святі (бал 44.4), і жодна фонетика їх не зблизить.
Такі пари живуть окремим шаром і вмикаються прапорцем --folk. За
замовчуванням шар вимкнений: на чужому матеріалі він злипає двох різних жінок,
а хибний позитив коштує дорожче за пропущений — пропущене шукають далі, а
зліплене вважають знайденим і закривають напрям.
🔴 Кожен хіт несе stem_origin. Значення folk означає, що зв'язок
біографічний, а не орфографічний: така знахідка сама по собі нічого не
доводить, доки не показано, що йдеться про ту саму людину.
Свої пари додаються в просторі — config/folk_names.yaml:
Мотрона: [Матрёна, Мотря]
🔑 Склейка розірваного прізвища¶
Прізвище на межі рядка розривається переносом, і жодна половинка сама по собі не схожа на ціле. Пошук тримає хвости трьох попередніх рядків і пробує зшити їх із початком поточного.
Чому саме трьох, а не одного: у табличних бланках (сповідки, ревізії, формуляри) сегментація зшиває колонки, і половинки розходяться на два-три рядки. З вікном в один рядок такі записи не знаходяться взагалі.
⚠ Далекі склейки суворіші за сусідню. Через рядок-два половинки злітаються вже не за законом переносу, а випадково — і без цієї суворості пошук почав би знаходити прізвище в будь-якому шумі.
Практичний наслідок для тебе: не роби склейку руками. Побачивши в тексті обірваний токен, не дописуй його — це вже зроблено, і зроблено з порогами, які перевірені на контрольних запитах.
🔑 Вікно замість рядка¶
search.run має поле context (типово 1): кожен хіт приходить із
сусідніми рядками, а не голим рядком.
Це не зручність. Рядок сам по собі не розрізняє прізвищ зі спільним коренем, а в одній парафії їх буває кілька — заміряно на метриках одного села: 78 кандидатів верхівки розклались на три різні роди з тим самим коренем плюс причт, і за самим рядком вони зливаються в купу однаково правдоподібних хітів.
Розрізняє їх сусідство:
↑ Балтскаго Повѣта Села Ковалевскаго ← географія стоїть вище
» Дьячисъ Григорій Ковалевскій сынъ Свя ← сам хіт обривається
↓ щунническій получившей удостость ← слово продовжується нижче
⚠ Вікно розсувне, а не ±N рядків. Огризок контекстом не вважається: сусідній рядок «на», «и», «3» не пояснює нічого, тож вікно розсувається далі, доки не набереться змістовного. Без цього контекст виявляється порожнім рівно там, де він найпотрібніший — між колонками щільного формуляра.
🔑 Другий голос поруч¶
Якщо справу читано двома рушіями, до хіта додається читання другого на тому самому рядку:
» Дьячисъ Григорій Ковалевскій сынъ Свя
2-й голос: Дьячисъ Григр̆ Ковааевскіи сынъ све
Збіг голосів означає надійне читання; розбіжність — сигнал, а не шум. Рушій із мовною моделлю підставляє правдоподібне слово, а другий судить кадри незалежно й калічить локально, зберігаючи корінь. Розбіжність саме на прізвищі (як вище: «Ковалевскій» проти «Ковааевскіи») означає, що ознака в пікселях — і вирішувати має око, а не третій алгоритм.
🛑 Але два голоси підтверджують читання, а не приналежність. Те, що обидва прочитали прізвище однаково, не робить особу вашою.
Поріг схожості¶
thresh за замовчуванням 80 зі 100. Нижче — більше шуму, вище — губляться саме
ті спотворені форми, по які пошук і кликали.
🔴 Не піднімай поріг, щоб «прибрати шум». Рушій калічить середину слова
сильніше за краї, тож найцінніші кандидати мають бал ближче до порогу, ніж
очевидні. Замість підняття порогу — ранжуй видачу (workflows.md, крок 3).
⚠ Окремо: короткі токени відсіюються довжиною (одиночний — від чотирьох літер, пара — від шести сумарно). Спроба додатково глушити «рядки-огризки» з волокон паперу перевірялась заміром і дала 0.1% менше кандидатів при нулі втрачених хітів — тобто фільтр не потрібен, а от глушіння такого рядка разом із його хвостом з'їдало справжні склейки.
Чого в пошуку немає¶
Це чесна межа версії, а не прогалина в документації.
| немає | що це було б | що робити натомість |
|---|---|---|
| канал за топонімом у декоді | «чи бачить машинний текст село, яке точно там є» — знаменник для нуля | звичайний запит назвою села; географію звіряти з каталогом. У виписаному й розібраному топонім має власну вісь — axis=place |
| канал за складом двору у списку | двір сповідки чи ревізії, де родина — дванадцять рядків поспіль | канал запису ловить запис метрики (смуга шести рядків); двір довшої форми — читати сторінку цілком навколо знайденого |
| канал за станом + іменем із вагою | «однодворець + Іосиф», зважене частотою слова в книзі | nysh text near "однодворецъ" "Іосифъ" — пара у вікні рядків, без ваги: часте слово стану стоїть на кожному аркуші |
| розрив між колонками окремим каналом | коли прізвище розірване не переносом, а версткою | склейка в три рядки плюс вікно контексту покривають більшу частину цього; ознаки з різних колонок одного запису зводить канал запису |
| перевірка віку/дат кандидата | «чи міг цей запис бути нашою особою» | арифметика документа вручну; цифри з декоду не факт |
🛑 Якщо людина просить «прочешіть повіт» або «знайдіть усі згадки роду в
фонді» — скажи прямо, що в цій версії є три канали роду (прізвище, імена й
запис; два останні — у межах справи), пара слів (text near) і три сховища. Обіцяти
багатоканальний прочіс, а потім видати нуль з одного каналу — помилка,
яку дорого виправляти: цей нуль виглядатиме як вичерпна відповідь.
Як читати нуль по кожному сховищу¶
Разом із результатом приходить попередження. Читай його, а не лише число:
zero_with_denominator— «не знайшлось у N прогонах (M сторінок)». Це справжній нуль, і в звіті він так і пишеться: з N і M.no_denominator— не шукало ніщо. Звітувати «немає» не можна.- попередження про метод — якщо сторінки заносились із позначкою «читав лише декод», їхній вміст успадкував помилки рушія.
І головне, що не приходить попередженням: нуль у decode не покриває
сторінок, яких ніхто не читав машиною. Скільки їх — питай cases.list
і pages.status, а не пошук.