Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Подготовлены толстые книги ВП СССР #9

Closed
iprst opened this issue May 8, 2023 · 31 comments
Closed

Подготовлены толстые книги ВП СССР #9

iprst opened this issue May 8, 2023 · 31 comments
Assignees

Comments

@iprst
Copy link
Collaborator

iprst commented May 8, 2023

Обработаны 50 толстых книг ВП СССР без запрета.
Все книги в двух форматах docx и txt.
В книгах удалены заголовки страниц, их графическое оформление и нумерация.
Форматирование текста сохранено в docx и удалено в txt.
Все сноски преобразованы в динамические примечания после окончания книги, а затем в текст.

Куда загружать?

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Может пока на диск загрузить? Я не знаю, нужна ли работа с ними в гите. Сами docх не распознаются гитом и будут как целые файлы храниться, без версий.
А какая у нас еще цель по этим подготовленным книгам, кроме как обработать их добавить в поиск? Т.е., например, размещаем их публично и указываем, что эти книги обработаны и добавлены в поиск.

Можно сделать и репозиторий. Чисто технически я пока не вижу для чего они должны быть в гите. Т.е. пока видится, что в этом нет необходимости, программной. Но с другой стороны почему бы и нет.
Диск? Или делаем репозиторий. Позже можно будет их выгрузить в статик cdn домен, но много позже, не сейчас.

UPD: На ваш выбор. Если появиться необходимость перенесём.

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Можно сделать и репозиторий. Чисто технически я пока не вижу для чего они должны быть в гите. Т.е. пока видится, что в этом нет необходимости, программной. Но с другой стороны почему бы и нет.

Репозиторий логичен в плане хронологии движения файлов внутри системы и какой-то централизации. Вопрос размещения в основном задан в векторе — а где книги после индексации будут храниться в принципе? Кроме проиндексированной базы нигде? Тогда исходники нужно сразу подтянуть к версии парсера, который книги обработает для представления на страницах выдачи, как-то так себе это представляю.

Общий вес папки примерно 50 Мб, то есть книги за счёт удаления внутренних ссылок в сносках и картинок резко уменьшились раза так в три по сравнению с оригинальным размером архива медиамеры. В архив пока не добавлены «Основы социологии» и все аналитические записки, впрочем АЗ по большей часте включены в книги-сборники «Вехи» и «Концептуальная власть», но всё что вышло позже в любом случае потребуется обработать. Как будет момент пополню репозиторий.

Предлагаю сделать версию репозитория парсера «под книги» и загрузить туда.

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Хорошо.
https://github.com/audetv/book-parser

Папка books. отправил приглашение

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Просто загружу папку VPSSSR в которой две директории DOCX и TXT, в них по 50 файлов, названных по-русски, это нормально? Или перевести в латиницу?

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Просто загружу папку VPSSSR в которой две директории DOCX и TXT, в них по 50 файлов, названных по-русски, это нормально? Или перевести в латиницу?

Да, хорошо VPSSSR и пусть будут на русском названия, посмотрим как пойдет работа, чем будет мешать.

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Загружены толстые книги ВП СССР.

@iprst iprst self-assigned this May 8, 2023
@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Какие будут соображения по схеме записи в базу, схеме поиска?

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Книгу поделить на заголовки, параграфы, сноски (ещё есть таблицы и формулы, пока не знаю, что с ними делать технически).
Каждую такую сущность добавить в индекс каждому заголовку и параграфу присваивать номер, чтобы можно было восстановить последовательность при необходимости. Это легко сделать парсером и записать в БД и в индекс поиска.

Надо решить: будем ли мы делать с книгами, что то типа как сейчас сделаны вопросы или большая сводная тема, т.е. будем ли дублировать у себя представление книги, чтобы ее можно было читать. Например, ссылка: перейти к книге, и ссылка, как вы писали в теме концепции связанности:

И.Я. Новиков, С.Б. Стечкин, Основы теории всплесков, УМН, 53 (1998), no 6, 53--128

Во только как страницы сохранить и нужно ли их хранить? Т.е. не понятно, мы же не бумажные сканы оцифровываем и книги с isbn. В общем, со страницами не знаю. В электронной версии вроде бы и не нужны страниц, тем более, шрифт экран, страница это нечто гибкое плавающий параметр.

Возможно надо давать ссылку на файл с которого оцифрована книга.

ИД Книга,  наименование, автор, информация, Ссылка (url), Файл, Файлы (изображения, другие файлы)
ИД Заголовок, ИД Параграф, ИД Сноска (Глава? Раздел?)  (Примечания?) 

Ещё есть главы и разделы их по идее тоже можно выделить, но надо подумать как. они по сути своей могут быть в некотором виде категориями. Дерево категорий. в книге. Т.е. сущность можно назвать категория и создавать для каждого типа свои категории со своим ИД И этот справочник сделать общим для всех сущностей. Но я пока не знаю как это сделать парсером. Например, читать оглавление и создать категории, но внутри в xml нету привязки к страницам. они у каждого кто смотрит файл формируются индивидуально. Т.е. страницы - это вроде как не жестко зашитое в структуру книги правило. Со страницами надо разбираться. Я когда осенью смотрел и делал пробную версию, страниц в схеме xml не нашел.

Ещё могут быть плоские списки - категории/тэги, без ветвления. Книга, Статья, МО, Архивный документ, (хотя это уже и типы могут быть). Т.е. по сути такая структура сейчас используется для хранения контента на сайтах. Как бы и ничего нового)

Про структуру книги и вообще сущности надо бы подумать. Хорошо бы подогнать все под одну структуру, и события и новости и вопросы. т.е. сделать универсальную сущность но с типам.

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Технически в мантикору можно подключить для поиска сразу несколько таблиц. Т.е. можно создать под каждый тип контента свою таблицу( вопросы, книги, новости, документы). и так было бы проще работать и я надеюсь, что в процессе не выявится какого либо бага, но я тестировал подключал 2 таблицы одновременно, не больше 2х... Но структура таблиц (столбы) по хорошему должна быть идентичной, я не проверял, но это логично. Я подключал для теста у себя локально 2 словаря вместе концептуальный и обычный в один поиск и они работали.
Надо провести тест по разным таблицам с разными полями.

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Иначе придется делать некий оркестратор над таблицами, управляющую структуру, которая буде принимать на вход запрос отправлять по нужным таблицам, собирать ответ и компоновать его в выдачу. Т.е. это все решаемо, будет очень сложно но решаемо) я так вижу.

UPD Или собирать все в одну таблицу, но это миллионы записей, что будет если надо пересобрать индекс.. сколько это займет времени? Надо придумать более продвинутый и производительный способ, чем сейчас для обновления индекса, хотя сейчас это уже 10-15 мин, на локальном минут 7 и это 360к записей, а их будет в разы больше. Пересобрать весь индекс это может быть долго. Лучше делить на таблицы, и я надеюсь, для этого все предусмотрено в мантикоре, просто плохо написано в доках)

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Книгу поделить на заголовки, параграфы, сноски (ещё есть таблицы и формулы, пока не знаю, что с ними делать технически).
Каждую такую сущность добавить в индекс каждому заголовку и параграфу присваивать номер, чтобы можно было восстановить последовательность при необходимости. Это легко сделать парсером и записать в БД и в индекс поиска.

Сейчас книги приведены более-менее к текстовому виду — книга это единый текст, в котором есть заголовки, абзацы и имена сносок римскими цифрами в квадратных скобках, сами сноски превращены в текст и являются примечаниями. Ворд как текстовый процессор не позволяет вернуть текст постраничной сноски внутрь текста (например в скобках или отдельной фразой после ключевого слова) — существует только возможность сделать из постраничных сносок глобальные в конце текста, а их далее превратить в текст, при этом присвоив им новые глобальные имена (римские цифры в квадратных скобках). Поэтому я думал, что позже можно будет заменить номера примечаний внутри основного текса на собственно текст примечаний.

Пример:

…расхождения могут показаться незначительными, но как будет показано дальше «от малых причин бывают большие последствия»[XVIII]


…[XVIII] Афоризм К.Пруткова.

Должно превратиться в:

…расхождения могут показаться незначительными, но как будет показано дальше «от малых причин бывают большие последствия»[Афоризм К.Пруткова.]

Это будет за два порядка более читабельно, чем то, как представлены книги в текущий момент. К слову, пока редактировал было обнаружено, что бесконечным обилием сносок страдает подавляющее большинство книг, кроме буквально единиц. Например, «Домик в Коломне», которую по-видимому писал Зазнобин самостоятельно, не имеет постраничных сносок вообще. Все сноски сделаны обычными текстовыми примечаниями в конце текста книги, и их очень немного.

Сноски это признак плохой организации текста. Идеальный текст это строка.

Получится ли у нас заменить номера в квадратных скобках содержанием соответствующих примечаний?

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

будем ли мы делать с книгами, что то типа как сейчас сделаны вопросы или большая сводная тема, т.е. будем ли дублировать у себя представление книги, чтобы ее можно было читать. Например, ссылка: перейти к книге, и ссылка, как вы писали в теме концепции связанности

Постраничные ссылки точно не нужны. Они и в текущей версии книг создаются процессором вёрстки — по-видимому вордом, который экспортировал все форматы. Те же электронные книги типа FB2 и EPUB не имеют страниц, ибо отображение текста целиков возложено на процессор устройства или алгоритм программы. То есть эта иерархия уже не работает в наше время. По сути решение нашего вопроса сводится к ответу на другой — как поделить книгу на строки логичной длины, которые станут записями в БД?

Можно пойти дальше и поразмышлять, что такое содержание книги и заголовки.

Возможно надо давать ссылку на файл с которого оцифрована книга.

Все книги кроме одной взяты с сайта медиамеры, где хранится архив публикаций ВП СССР. Единственное исключение — текст цензурированной Мёртвой Воды 2015 года, который взят с сайта zaznobin, только там нашлась doc версия, везде pdf.

ИД Книга, наименование, автор, информация, Ссылка (url), Файл, Файлы (изображения, другие файлы)

В настоящий момент все «файлы» кроме непосредственного текста убраны, включая изображения.

ИД Заголовок, ИД Параграф, ИД Сноска (Глава? Раздел?) (Примечания?)

В каждой книге своя конфигурация иерархии, поэтому я предлагаю не наследовать ничего из этого. Всё это просто калейдоскоп бесконечный. Нужно приводить к нормальному виду.

В идеале это будет строка, но у нас скорее всего получится:

заголовок
строка
строка
строка

заголовок
строка
строка
строка

При этом заголовок это сущность чисто макетирования, представления. Исходить нужно сразу из сценариев работы с текстами, которые подразумеваются при поиске.

  1. Найти книгу, в которой есть слова «ааа», «ббб», «ввв».
  2. Найти книгу, в которой есть строка, содержащая слова «ааа», «ббб», «ввв».
  3. Найти строку «ааа, ббб, ввв, ггг, ддд».
  4. Найти заголовок «ААА».
  5. Сколько раз в книге встречается слово «ааа».
  6. В какой книге чаще всего встречаются слова «ааа», «ббб», «ввв».

И тому подобные схемы. То есть нужно исходить из реальных случаев применения поиска, это не должен быть абстрактный «просто поиск».

Ещё могут быть плоские списки - категории/тэги, без ветвления. Книга, Статья, МО, Архивный документ, (хотя это уже и типы могут быть). Т.е. по сути такая структура сейчас используется для хранения контента на сайтах. Как бы и ничего нового)

Про структуру книги и вообще сущности надо бы подумать. Хорошо бы подогнать все под одну структуру, и события и новости и вопросы. т.е. сделать универсальную сущность но с типам.

Именно так и нужно сделать. Это должно быть плоское типизированное представление. В духе сущность, строка, атрибуты. Можно представить книгу как упорядоченный набор комментариев автора «ВП СССР» на виртуальном сайте и пользоваться существующими в базе критериями сущностей.

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Получится ли у нас заменить номера в квадратных скобках содержанием соответствующих примечаний?

Думаю, да. Из того, что я посмотрел сейчас, первый код это параграф и внутри него тестовая сноска [CCCLVI], т.е. распарсить это можно. Сам текст и номер ссылки в одном параграфе их соединяем.

Далее параграф со ссылкой. Т.е. технически структура понятная, можно распарсить и соединить.

Так что думаю да.

Т.е. у нас эти 2 параграфа должны в поиске находиться вместе? Ищем: «Рабы, повинуйтесь господам своим» и находим в поиске один параграф, которые сделал парсер из 2ух?

Или это раздельные записи и храним раздельно, и показываем раздельно? я так понял, что нет. Хорошо.

Еще не понятно. Мы книгу будем показывать полностью, или только части(параграфы) в поиске? Только поиск или и книги сами на сайте. Надо над этим подумать.
Хотя это наверное не так важно, т.к. структура книги будет храниться в БД, номера и связи, и книгу по структуре можно восстановить при необходимости.

<w:p w14:paraId="0107EF2E" w14:textId="26CBB52D" w:rsidR="001E017F" w:rsidRDefault="001E017F" w:rsidP="001E017F">
<w:pPr>
<w:pStyle w:val="a4"/>
</w:pPr>
<w:r>
<w:t>«Рабы, повинуйтесь господам своим по плоти со страхом и трепетом, в простоте сердца вашего, как Христу, не с видимою только услужливостью, как человекоугодники, но как рабы Христовы, исполняя волю Божию от души, служа с усердием, как Господу, а не как человекам, зная, что каждый получит от Господа по мере добра, которое он сделал, раб ли, или свободный» (К Ефесянам послание апостола Павла, 6:5</w:t>
</w:r>
<w:r w:rsidRPr="00DF1280">
<w:t>-</w:t>
</w:r>
<w:r>
<w:t>8)</w:t>
</w:r>
<w:r w:rsidRPr="001E017F">
<w:rPr>
<w:vertAlign w:val="superscript"/>
</w:rPr>
<w:t>[CCCLVI]</w:t>
</w:r>
<w:r>
<w:t>.</w:t>
</w:r>
</w:p>
<w:p w14:paraId="56FEBD16" w14:textId="0CCDB560" w:rsidR="001E017F" w:rsidRDefault="001E017F" w:rsidP="001E017F">
<w:r>
<w:t>[CCCLVI] Это ещё одно место в Новом Завете, которое, будучи вырванным из общего исторического контекста, о котором церкви всегда умалчивают, требует от “христианина”, живущего церковной жизнью, подчиниться иудейскому расизму и ростовщическому господству над планетой.</w:t>
</w:r>
</w:p>

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Еще не понятно. Мы книгу будем показывать полностью, или только части(параграфы) в поиске? Только поиск или и книги сами на сайте. Надо над этим подумать.
Хотя это наверное не так важно, т.к. структура книги будет храниться в БД, номера и связи, и книгу по структуре можно восстановить при необходимости.

Как выше предложил, давайте представим книгу как «тему на ФКТ» в которой один автор «ВП СССР», где глав как таковых нет, а есть строки (т.е. абзацы / параграфы), и «метки» заголовков, которые по сути являются якорями типа хайлайт-ссылки. Таким образом мы получаем набор сущностей — «тема = книга», «автор = автор», «комментарий ~ страница», «абзац = строка» и «заголовок = метка-ссылка».

В результате, что мы можем выдать в поиске — например набор «страниц = комментариев», содержащих запрос «ааа». В оформлении выдачи можно дать название книги (а-ля название темы-вопроса), и так далее. Можно ли сделать запрос «покажи всю книгу»? Наверное это не сложно, если у «комментариев» есть какой-то порядковый ID (например сейчас это может быть «дата комментария») и мы знаем что «книга = тема». И тому подобное.

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

По сути решение нашего вопроса сводится к ответу на другой — как поделить книгу на строки логичной длины, которые станут записями в БД?

Возможно и не надо делить книгу на логические куски, надо это проверить, так как ее можно закинуть полностью как текст в таблицу и искать по всей книге, А higlight подсветка найденного работает как массив найденных вхождений, т.е. подсвеченных фрагментов будет много. Надо будет это проверить, я сейчас пока не уверен, что смог это описать, но когда с комментариями работал я включил режим подсветки всего содержимого найденного, а можно оставить например 200 символов слева справа, и таких кусков найденных будет по идее много.
Не знаю надо это проверить возможно это вообще не так работает как мне показалось.

А так деление по параграфам word сделать легче всего, будет ли этакая схема находить нужное надо тоже проверять.

По другому, надо думать.

UPD Надо проверить хайлайты как работают.

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Лучше делить на таблицы, и я надеюсь, для этого все предусмотрено в мантикоре, просто плохо написано в доках)

Возможно имеет смысл установить это прямо в ближайшее время, заодно пройтись по другим техническим ограничениям мантикоры.

Возможно и не надо делить книгу на логические куски, надо это проверить, так как ее можно закинуть полностью как текст в таблицу и искать по всей книге,

А что будет результатом такой выдачи? Допустим, ищем «триединство» и желаем, условно, получить список абзацев с этим словом из любой книги. Получится выдать одни только абзацы с этим словом?

Представим, что у нас поиск ищет «триединство» сразу в книгах, и в комментариях. Как будет выглядеть выдача? Можно привести к единообразному результату?

@audetv
Copy link
Collaborator

audetv commented May 8, 2023

Представим, что у нас поиск ищет «триединство» сразу в книгах, и в комментариях. Как будет выглядеть выдача?

Не знаю, надо будет загрузить пару книг и посмотреть. Только в постмане, без реализации в коде. И посмотреть, что будет в хайлайтах.
Хорошо, понятно, что надо будет в ближайшее время проверить.

Возможно имеет смысл установить это прямо в ближайшее время, заодно пройтись по другим техническим ограничениям мантикоры.

Хорошо бы загрузить все по мантикоре в голову как в матрице, но увы. Вектор понятен, буду дальше изучать, освоим.

@iprst
Copy link
Collaborator Author

iprst commented May 8, 2023

Хорошо бы загрузить все по мантикоре в голову как в матрице, но увы. Вектор понятен, буду дальше изучать, освоим.

Можно исходить из освоенного — как сделать рабочий поиск «прямо сейчас» самым прямолинейным способом? Иногда готовый на 50% вариант, но сейчас, лучше, чем идеальный, но через полгода.

@audetv
Copy link
Collaborator

audetv commented May 12, 2023

Добавил тестовые наработки по поиску книг в https://github.com/audetv/book-parser
Разместил инструкцию в readme, как можно попробовать поиск в мантикоре с Postman.

@iprst
Copy link
Collaborator Author

iprst commented May 12, 2023

Отлично.
Что тестируем?
На что нужно обратить внимание?
Изобретаем сценарии?
Впоследствие можно будет заменить номер сноски в квадратных скобках на текст этой сноски?

@audetv
Copy link
Collaborator

audetv commented May 12, 2023

Надо потестировать, поискать в книгах что-то, возможно, что раньше искали, и посмотреть выдачу, Это конечно в постмане не так наглядно, но пока, что есть. Думаю надо обратить внимание, на параграфы на выдачу, т.е. понять насколько данная модель разбиения на параграфы и хранения по одному параграфу соответствует ожидаемым результатам. Иногда попадаются мелкие параграфы, или заголовки, и они ищутся отдельной единицей, хотя на мой взгляд этом вроде нет ничего такого, чтобы сбивало с толку. Вроде вполне понятно.

Но если сравнивать с поиском по комментарием, который как запись в бд, то все таки многие комментарии являются законченными смысловыми единицами. т.е. получил в выдаче, прочитал и порой нет даже необходимости смотреть, а что там в оригинале, в контексте темы вопроса. А с книгой мне попадались варианты, когда хочется прочитать продолжение, а оно в следующем абзаце, который не попал в выдачу. И был пример с цитатой «Не удастся запустить и двух имитаторов-провокаторов» , ищется «двух имитаторов» вполне нормально выглядит.

В общем попробовать поискать и далее подумаем, что с этим делать. Технически можно показывать / скрывать, например по кнопке какой-нибудь типа подробнее, предыдущие пару абзацев и следующие пару абзацев.

Да сценарии поизобретать, поломать поиск запросами.

В выдаче точно еще есть некоторые параграфы мусорные их надо будет выявлять и отсеивать. Всякие (* * *) , ________, ------------ и прочее)

Еще есть оглавления, хотя вроде не особо мешает оно, если попадется в выдаче.

Номер сноски думаю можно будет заменить, я пока не приступал к реализации этого, с ходу не совсем просто, так как файл сейчас читается по параграфу в буфер памяти, т.е. некий reader идет в цикле по параграфам до конца файла, разбирает его и возвращает строку, которую сразу пишет в бд, далее следующий параграф.
Надо доработать: reader сначала читает всю книгу в память, в буфер, складывает ее по параграфам в срез с номерами и строками(параграфами), привязывает сноски. Потом когда к концу файла reader дойдёт до сносок, он определяет номер, ищет его в срезе и добавляет туда еще параграф в скобки, и записывает в бд. (Каналы и горутины... ещё для меня сложно, но возможно, надо делать, не набита рука)

Или пишет как и раньше в бд, но потом когда находит сноску, возвращает ее, ищет по сноске эту запись в мантикоре, и её обновляет. Этот второй сценарий проще сломать, получить неожидаемый результат, хотя не знаю, возможно не прав, надо пробовать

В общем, алгоритм надо будет поменять.

@iprst
Copy link
Collaborator Author

iprst commented May 12, 2023

В выдаче точно еще есть некоторые параграфы мусорные их надо будет выявлять и отсеивать. Всякие (* * *) , ________, ------------ и прочее)

Это можно сделать в тексте.
В базе, возможно, удалить такие записи проще, отсортировав их по размеру.

@iprst
Copy link
Collaborator Author

iprst commented May 12, 2023

надо обратить внимание, на параграфы на выдачу, т.е. понять насколько данная модель разбиения на параграфы и хранения по одному параграфу соответствует ожидаемым результатам

Зависит от того, что подразумевается под словом параграф. Если это текст между двумя жёсткими переносами строки, то бишь «предложение», то поиск скорее всего не будет обладать достаточной полнотой. Например, если ищется условная «страница», на которой упомянуты три-четыре слова не по соседству, то есть ищется некая «тема» по набору ключевых слов.

Можно ли каким-то образом оперировать размерами окна поиска? Например «искать в пяти ближайших строках» или что-то подобное?

Есть вариант разбить книги на отрывки вручную.

@audetv
Copy link
Collaborator

audetv commented May 12, 2023

Я имел ввиду «технический параграф» в xml файле в ворд. Вот пример параграфа:

<p>Не удастся запустить и двух имитаторов-провокаторов для изображения перед публикой деятельности в тандемном режиме. Дело в том, что тандемный режим деятельности — средство разрешения <i>реально существующих</i> проблем. Выдумать несуществующую проблему и показать её как якобы реально существующую в среде тех, кто сам занимается действительно концептуальной деятельностью, не удастся; <i>умышленно осознанно </i>создать проблему там, где её реально не было, — это будет выявлено и расценено как целенаправленное вредительство. Придётся взять реальную и актуальную для Концепции общественной безопасности проблему и разрешить её, поскольку отсутствие результата — явное выражение неспособности войти в тандемный режим, и соответственно — одно из выражений неспособности к концептуальной деятельности.</p>

Грубо строка законченная Enter, перенос троки \r\n, видимо да - жесткий перенос. Может быть несколько предложений, заканчивающихся точкой.

Можно искать и по всей книге, т.е. занести всю книгу в бд, как единицу, это надо тоже проверять. Я так не делал еще. Можно разбить по главам.

Я так понимаю, движок будет выдавать первыми те записи, слова в которых стоят к другу другу ближе, а те которые будут иметь между собой большое расстояние получат более низкий вес.

Если занести в базу книгу как единицу, тот поиск выдаст всю книгу, и отдельный массив подсветок highlights, подсветка найденных фраз, +- сколько то символов (мало символов. надо пробовать и считать, но вроде не более 120 символов, выглядит как яндекс-гугл поиск, подсветка небольшого текста и далее обычный сценарий это ссылка на документ оригинал, с которым работаешь, но это не совсем наш вариант. так?

Или поиск может выдать все символы в найденном без ограничений, так сейчас сделана подсветка в поиске по комментариям, по сути выдается highlight 'limit' 0, 'no_match_size' 0, . По идее, если сработает, то будет вся книга, которую надо скролить в поисках подсвеченных фраз. Все это надо проверять.

Можно ли каким-то образом оперировать размерами окна поиска? Например «искать в пяти ближайших строках» или что-то подобное?

Не видел такой настройки, ищет по таблице в полях с типом text, и может выдать запись из таблицы как единицу найденную целиком, но иметь еще массив подсвеченных найденных фраз. Это я про структуру ответа json

Фрагмент запроса поиска:
 "query": {
        "bool": {
            "must": [
                {
                    "match": { "_all" : "двух имитаторов явное"}
                }
            ]
        }
    }

Фрагмент ответа в подсветке 2 записи предлагается найденных в одной единице ( в данном случае прагараф):
  {
                "_id": "3460893741995944220",
                "_score": 1571,
                "_source": {
                    "position": 907,
                    "type": 1,
                    "datetime": 0,
                    "book": "Последний гамбит.docx",
                    "text": "<p>Можно сказать, что на небольшой территории ашрама в миниатюре был представлен почти весь мир. Делегации из разных стран в своём составе насчитывали от двух-трёх до десятка и более человек и к тому же их представители носили на шее отличительные знаки в виде галстука-косынки с признаками национального флага. Холмс обратил внимание, что стоимость проживания, питания, одежды были чисто символическими, что невольно наводило на мысль о явной убыточности всего заведения. Да, несомненно, здесь что-то «варилось» и не без участия очень богатых спонсоров.</p>"
                },
                "highlight": {
                    "text": [
                        " составе насчитывали от <b>двух</b>-трёх до десятка ",
                        "наводило на мысль о <b>явной</b> убыточности всего заведения. "
                    ]
                }
            },
            {

В базе, возможно, удалить такие записи проще, отсортировав их по размеру.

Я не знаю, как сделать такой запрос в Манткоре, это не обычная база, она сильно отличается от привычных мне реляционных типа mysql postgres. Хотя даже так, я ранее не программировал сценарии полнотекстового поиска. Для меня это не обычно, но задумался, как сделать запрос в обычную для меня бд с сортировкой по длине строки... не делал никогда такого.

Есть вариант разбить книги на отрывки вручную.

Возможно это будет самый лучший вариант.

Я поэтому и разместил вариант тестовый, что если будет возможность запустить и в постмане поискать, то вам видимо сразу будет видно, что так или что совсем не так. Если не получиться в постмане запустсить, то учитывая все вышеизложенное, буду обдумывать варианты с фрагментами, и организацию простого сайта (фронтенд) для поиска. И пробывать на нём эти варианты: с главами, с параграфами, с целой книгой или еще как то.

@audetv
Copy link
Collaborator

audetv commented May 12, 2023

Т.е. думаю , что как раз по всей книге искать мантикора будет нормально, а вот как результат поиска показать, я пока не понимаю. Так как результат поиска по книге (как единица, запись в таблице) это вся книга.
Возможно надо загрузить всю книгу и пробовать мучать настройки подсветки, добиться результата, где много фрагментов, в которых много символов (1000 штук, я придумал это число) и эти фрагменты показывать. В общем с подсветкой результатов надо по разбираться мне ещё.

@iprst
Copy link
Collaborator Author

iprst commented May 12, 2023

Я имел ввиду «технический параграф» в xml файле в ворд. Вот пример параграфа:

Понял. Можно считать параграф = абзацу = фразе.

Жёсткий перенос это когда введён энтер или подобный ключ, например тег <p> в html, то бишь этот перенос присутствует в любом формате и типе просмотра строки. Мягкий перенос, соответственно, когда такого ключа нет, а перенос осуществляется границей экрана, листа и тд, в общем, то, что включается и отключается в текстовых редакторах как опция, в том числе в гитхабе.

Я так понимаю, движок будет выдавать первыми те записи, слова в которых стоят к другу другу ближе, а те которые будут иметь между собой большое расстояние получат более низкий вес.

Это где-то описано, или это имеет смысл проверить вручную на опыте? Взять например книгу средней длины и провести эксперимент.

Если занести в базу книгу как единицу, тот поиск выдаст всю книгу, и отдельный массив подсветок highlights, подсветка найденных фраз, +- сколько то символов (мало символов. надо пробовать и считать, но вроде не более 120 символов, выглядит как яндекс-гугл поиск, подсветка небольшого текста и далее обычный сценарий это ссылка на документ оригинал, с которым работаешь, но это не совсем наш вариант. так?

У нас глобально два подхода. Либо изобретается прямо буквально то, что хочется изобразить с книгой, либо делаем наиболее близко к единообразию с поиском по сайту, по Кремлю и тд. Если взять официальные сайты и даже взять ФКТ, то длина записи (комментария или новости) одного и того же источника может различаться в тысячу раз, но это никогда не «книга». Нет ни одной отдельной записи, которая бы весила мегабайт в бинарном виде. Есть предположение, что запись, размером с книгу, не будет удобной формой хранения, а выдача результатов в окне 120 символов скорее всего не будет отражать то, что ожидается от поиска по книге. Рудиментарно — да, возможно, типа «найди мне триединство» и в выдаче будет двадцать твитов. Но скорее всего это не оптимальный сценарий. Скажем так, это движение в сторону калейдоскопа, а мы скорее всего пытаемся сделать мозаику. А мозаику требуется проектировать.

Парсер, помещающий docx в базу, различает уровни заголовков? А что если зайти в docx и вручную проставить специально изобретённый маркер для деления книги на части?

ищет по таблице в полях с типом text, и может выдать запись из таблицы как единицу найденную целиком

Значит готового функционала нет. Подразумевается, что если есть найденная строка, то у неё есть ID который связан с предыдущей и следующей строкой. Тогда в результатых выдачи можно было бы отдавать найденную строку N и контекст — строку N–1 и строку N+1. Если ID можно сделать упорядоченными, конечно. Можно представить, что текст писался автором в хронологической последовательности и тогда можно использовать функционал типа «номер комментария» в поиске по ФКТ. Если это короткий путь, или тем более самый короткий, то такая схема может иметь смысл.

Для меня это не обычно, но задумался, как сделать запрос в обычную для меня бд с сортировкой по длине строки

Возможно я нафантазировал лишнего, представляя БД как что-то подобное таблицам гугла или экселя. Там это решается достаточно легко, есть стандартная функция, вычислающая количество знаков в ячейке, и по результатам можно сортировать в любом направлении или фильтровать зависимым фильтом.

Можно все найденные ошибочные строки просто найти в текстовом редакторе и поубивать их там. Нужно просто знать какой-то ключ для их обнаружения.

Если не получиться в постмане запустсить, то учитывая все вышеизложенное, буду обдумывать варианты с фрагментами, и организацию простого сайта (фронтенд) для поиска. И пробывать на нём эти варианты: с главами, с параграфами, с целой книгой или еще как то.

Да я думаю всё будет в постмане работать, просто пока не могу проверить, завтра. А фронтенд не будет лишним вообще в любом случае. Более того, фрондент хотя бы в черновой форме или даже на уровне наброска решит некоторые проблемы проектирования выдачи результатов на уровне дизайна их отображения. Ведь сразу потребуется подумать — а как собственно эти результаты должны выглядеть на странице, чтобы быть полезными.

Когда я пробовал сделать такой поиск на локальном компе, я пытался использовать официальный wiki движок, в котором есть модуль поиска. Он нормально отдаёт результаты, но судя по всему это довольно похоже на мантикору, текст результата составляет примерно 170 символов, то есть чуть больше, но мне кажется этого мало для контекста:
https://en.wikipedia.org/w/index.php?search=апрель+самолёт+судно

Будет здорово, если в результат отдавать не менее тысячи символов.

Т.е. думаю , что как раз по всей книге искать мантикора будет нормально, а вот как результат поиска показать, я пока не понимаю. Так как результат поиска по книге (как единица, запись в таблице) это вся книга.
Возможно надо загрузить всю книгу и пробовать мучать настройки подсветки, добиться результата, где много фрагментов, в которых много символов (1000 штук, я придумал это число) и эти фрагменты показывать. В общем с подсветкой результатов надо по разбираться мне ещё.

Если книга имеет собственную страницу, и при поиске организуется хайлайт в тексте, нужной нам длины (тысяча или две тысячи символов и тд), то выдавать результаты можно в виде списке таких хайлайтов, которые будут являться ссылками на страницу книги с привязкой к подсвеченному тексту. Насколько это сложно, реализуемо ли это?

@audetv
Copy link
Collaborator

audetv commented May 13, 2023

Я так понимаю, движок будет выдавать первыми те записи, слова в которых стоят к другу другу ближе, а те которые будут иметь между собой большое расстояние получат более низкий вес.

Это где-то описано, или это имеет смысл проверить вручную на опыте? Взять например книгу средней длины и провести эксперимент.

Не знаю, откуда то у меня такая мысль есть, вспоминаю. При чтении документации и разных статей мне попадалась информация про ранжирование и функции рейтинга, но так как это не было целью моего поиска, пропускалось, но в памяти осталось. Теперь надо будет специально поискать эту информацию, сделаю это.
Но! В любом случае, чтобы не писали в документации или статьях, надо брать и проверять, это просто факт, пишут одно, а по факту другое, или пишут так, что ничего не понятно непосвященному, проходили)
https://manual.manticoresearch.com/Functions/Searching_and_ranking_functions#MIN_TOP_SORTVAL()

Взять например книгу средней длины и провести эксперимент.

Да, надо так сделать.

Если взять официальные сайты и даже взять ФКТ, то длина записи (комментария или новости) одного и того же источника может различаться в тысячу раз, но это никогда не «книга». Нет ни одной отдельной записи, которая бы весила мегабайт в бинарном виде.

Интересная статистика: спарсенные текущей версией парсера по параграфам толстые книги это "total": 81917,
параграфов. Почти в 3 раза больше, чем сводная тема, и в 4.3 раза меньше чем 356 000 комментариев на ФКТ с 24 февраля 2016 г., тоже интересная дата, совпала с датой начал СВОДД.

Парсер, помещающий docx в базу, различает уровни заголовков? А что если зайти в docx и вручную проставить специально изобретённый маркер для деления книги на части?

Да, я вносил условия для различения уровней, по факту прасер читает структуру xml, в которой заголовки технически размечены, но структура оpenXml достаточно мудрёная https://learn.microsoft.com/ru-ru/office/open-xml/open-xml-sdk. Это целый новый мир. В общем это не просто H1, но различать можно. Более того он сейчас уже это делает. Те параграфы и html тэги, которые появляются в выдаче - это результат работы (преобразования парсера). Вот фрагмент кода условий из парсера :

if tt.Name.Local == "pStyle" {
				for _, attr := range tt.Attr {
					if attr.Value == "1" {
						headerTag = "h2"
					}
					if attr.Value == "2" {
						headerTag = "h3"
					}
				}
			}
			if tt.Name.Local == "b" {
				tag = "b"
			}
			if tt.Name.Local == "i" {
				tag = "i"
			}

Парсер проставил тэги, как я задал. Таким образом, можно по заголовкам разбить, или самим расставить нужные заголовки и по ним разбить текст на нужные фрагменты для сохранения в БД. Даже так подытожить, заголовки будет проще определять, чем парсить специальный изобретенный маркер. Для заголовков все есть, надо добавить только условия, для маркера придется написать специальный код.

Значит готового функционала нет. Подразумевается, что если есть найденная строка, то у неё есть ID который связан с предыдущей и следующей строкой. Тогда в результатых выдачи можно было бы отдавать найденную строку N и контекст — строку N–1 и строку N+1. Если ID можно сделать упорядоченными, конечно. Можно представить, что текст писался автором в хронологической последовательности и тогда можно использовать функционал типа «номер комментария» в поиске по ФКТ. Если это короткий путь, или тем более самый короткий, то такая схема может иметь смысл.

То что вы описали, я частично уже сделал. А именно каждой записи при сохранении присваивается порядковый номер, хронологически как шёл reader по тексту сверху вниз и пронумерован каждый параграф.
В postmane это field "position": 1000, (вместо 1000 порядковый номер параграфа). Т.е. сейчас книгу однозначно можно определить по наименованию книги: "book": "Форд и Сталин - о том, как жить по-человечески.docx", а параграф по "position": 1000. и этот фрагмент имеет свой ИД: "_id": "9081390343584298422",

{
                "_id": "9081390343584298422",
                "_score": 1,
                "_source": {
                    "position": 1000,
                    "type": 1,
                    "datetime": 0,
                    "book": "Форд и Сталин - о том, как жить по-человечески.docx",
                    "text": "<p>Об этом фильмы “Встречный” (о встречном плане и трудовом энтузиазме), “Кубанские казаки”, “Сказание о земле Сибирской”, “Большая семья” (по роману В.А.Кочетова “Журбины”), “Дело, которому ты служишь”, “Дорогой мой человек” (по романам Ю.П.Германа), “Добровольцы”, “Валерий Чкалов” и др. Были произведения и о том, как должно любить и защищать <b>свою</b> — народную — Советскую власть и социализм, <i>право на которые простой люд выстрадал и завоевал большой кровью в Великой Октябрьской социалистической революции и в гражданской войне</i> (“Броненосец «Потёмкин»”, “Чапаев”, “Оптимистическая трагедия”, “Тихий дон”, “Как закалялась сталь”, “Кортик”) и защитил в Великой Отечественной войне (“Повесть о настоящем человеке”, “Молодая гвардия”, “В окопах Сталинграда”, “Два капитана”)[CCLXXII].</p>"
                },
                "highlight": {
                    "text": []
                }
            },

Таким образом в поисковой выдаче нет проблем показать записи с position 999, 1000, 1001 (или чтобы было в общем 1000 символов) у системы есть для этого информация. Нужно только ей воспользоваться и правильно составить поисковую выдачу. Я примерно эту мысль пытался выразить ранее, но видимо много было в умолчаниях:

В общем попробовать поискать и далее подумаем, что с этим делать. Технически можно показывать / скрывать, например по кнопке какой-нибудь типа подробнее, предыдущие пару абзацев и следующие пару абзацев.

Проблема будет подсвечивать слова в этих параграфах, которые -1 и +1 ( или в общем 1000 символов), но надо подумать то, что проблема сейчас, подумал и нет проблем)) Возможно есть способы как это сделать, а возможно это и не надо подсвечивать. И в результатах поиска будет всё понятно.

Возможно я нафантазировал лишнего, представляя БД как что-то подобное таблицам гугла или экселя. Там это решается достаточно легко, есть стандартная функция, вычислающая количество знаков в ячейке, и по результатам можно сортировать в любом направлении или фильтровать зависимым фильтом.

Таблицы гугл эксель таблицы превосходят по функционалу и способам использования различные БД. То что в таблицах делается просто, в других приложениях, не в таблицах, сложнее, надо использовать БД и бизнес логику - еще какой-то код. Таблицы мощный инструмент для работы с небольшим кол-вом данных, десятками тысяч, а вот когда счет идет на сотни тысяч, то уже таблицы не подходят, так как их преимущества для небольших объемов данных становятся их недостатком. В реляционных БД, есть индексы, связи, join и прочее, что позволяет извлекать данные достаточно быстро, в том случае если они правильно записаны, по теории реляционной алгебры, а далее работает написанный сверху код - бизнес логика, который обрабатывает результаты запросов, комбинирует информацию и выдает итог.

Можно все найденные ошибочные строки просто найти в текстовом редакторе и поубивать их там. Нужно просто знать какой-то ключ для их обнаружения.

Все верно, если мы сможем этот ключ выразить лексически, то потом сможем и в коде в виде условий в парсере.
Или всё таки подготовить книги руками, для загрузки в БД пока без условий и ИИ))) Я когда начинал делать парсер еще осенью, представлял себе сценарий, что пользователь берет свой любой файл (docx или электронную книгу epub и прочие форматы), загружает на сервер, сервер обрабатывает и выдает результат уже в поиске, без танцев с приготовлениями файла, но сейчас понимаю, что это очень сложно реализовать, а главное, что такой вариант не имеет смысла по ПФУ. Если цель сделать парсер с ИИ любых книг, то да, но нам надо начать с толстых книг, и дальше будет видно. Так что похоже, что всё таки надо будет подготавливать файлы перед тем как переводить в БД. Мозаику требуется проектировать - это отличная мысль.

Да я думаю всё будет в постмане работать, просто пока не могу проверить, завтра. А фронтенд не будет лишним вообще в любом случае. Более того, фрондент хотя бы в черновой форме или даже на уровне наброска решит некоторые проблемы проектирования выдачи результатов на уровне дизайна их отображения. Ведь сразу потребуется подумать — а как собственно эти результаты должны выглядеть на странице, чтобы быть полезными.

Да в итоге надо будет это сделать - фронтенд. Я думаю, как только обсудим основные вопросы по книгам, придет время.

Если книга имеет собственную страницу, и при поиске организуется хайлайт в тексте, нужной нам длины (тысяча или две тысячи символов и тд), то выдавать результаты можно в виде списке таких хайлайтов, которые будут являться ссылками на страницу книги с привязкой к подсвеченному тексту. Насколько это сложно, реализуемо ли это?

Если предположим ,что разобрались с хайлайтами и добились в них 1000 символов, то остальное можно сделать, сейчас нечто подобное сделано с комментариями, когда есть ссылка в выдаче «посмотреть вопрос». Я как раз несколько раз ранее в обсуждениях по книгам задавался вопросом, а нужно ли дублировать книгу для чтения, чтобы перейти в нее из выдачи и продолжить чтение фрагмента, сейчас понимаю, что мой вопрос происходил вот из того, что мы сейчас обсуждаем, как связать результаты выдачи мантикоры с тем, что хотим в итоге показать пользователю.

Т.е. если подытожить, книгу похоже все таки надо разбить на фрагменты более мелкие, те же параграфы.
Даже если мы реализуем вариант, что книга проиндексирована целой единицей и мантикора ищет во всей книге, и выдаёт хайлайты на фрагменты книги, то нужно иметь доступ к этим фрагментам, т.е. параграфы должны быть пронумерованы - иметь индекс, чтобы мы могли составить любую выдачу и восстановить из БД целостность или создать новый фрагмент при необходимости: книга + комментарий + новость.

Надо провести тесты с целой книгой, и потом надо решить, индексируем ли целую книгу, или индексируем по главам, или же параграфы будут удовлетворять нашим условиям, и поиск будет давать нужный результат, а выдачу мы проектируем так как надо нам, а ни как выдает мантикора - вики.

@iprst
Copy link
Collaborator Author

iprst commented May 13, 2023

Проблема будет подсвечивать слова в этих параграфах, которые -1 и +1 ( или в общем 1000 символов), но надо подумать то, что проблема сейчас, подумал и нет проблем)) Возможно есть способы как это сделать, а возможно это и не надо подсвечивать. И в результатах поиска будет всё понятно.

Не нужно подсвечивать в контекстовых строках. Пусть хайлайт будет в центре, окружён контекстом без подсветки и всё будет понятно и очевидно, даже если в контексте будут ключевые слова.

Если предположим ,что разобрались с хайлайтами и добились в них 1000 символов, то остальное можно сделать

Значит нужно сделать, где-то на поддомене или в специальном разделе сайта для теста. И даже 1000 символов в текущей ситуации это условность — можно начать просто со строк, как они у вас сейчас вбиты в базу. Абзац любой длины и два его соседа.

@iprst
Copy link
Collaborator Author

iprst commented May 13, 2023

При чтении документации и разных статей мне попадалась информация про ранжирование и функции рейтинга, но так как это не было целью моего поиска, пропускалось, но в памяти осталось.

Этого ответа мне в целом достаточно, я это и имел в виду. Проверку можно не делать прямо сейчас, не горит, есть есть зашитые методы ранжирования, мы просто воспользуемся ими на текущий момент, а уже потом решим что с ними не так.

Взять например книгу средней длины и провести эксперимент.

Да, надо так сделать.

Пока не будем тратить на это время, лучше запустить минимальный набор как описано в конце вашего и в моём предыдущем комментариях.

Интересная статистика: спарсенные текущей версией парсера по параграфам толстые книги это "total": 81917, параграфов. Почти в 3 раза больше, чем сводная тема, и в 4.3 раза меньше чем 356 000 комментариев на ФКТ с 24 февраля 2016 г., тоже интересная дата, совпала с датой начал СВОДД.

Познавательно, спасибо. Юрий как-то спрашивал о том, нельзя ли какую-то статистику по сайту, подобную этой, по комментариям и посещениям самого сайта показать где-то на специальной страничке, просто чтобы у посетителей складывалось представление об объёмах и размерах.

Парсер проставил тэги, как я задал. Таким образом, можно по заголовкам разбить, или самим расставить нужные заголовки и по ним разбить текст на нужные фрагменты для сохранения в БД.

Отчасти мы это на самом деле протестировали — для выноса сносок в примечания мне приходилось оформлять новый раздел в каждом файле с заголовком ПРИМЕЧАНИЯ. Во всех книгах (возможно за исключением 1-2) я делал это по одной схеме — это был heading 1. То есть если раздел примечаний в конце каждой книги парсер распознал, значит можно работать с H1. Но пока что мы этого не будем делать, а сделаем первичный прототип как выше обсудили.

Таблицы гугл эксель таблицы превосходят по функционалу и способам использования различные БД.

Понял, тогда отбой. С другой стороны если базу экспортировать в csv, то можно сделать всю зачистку в таблицах, а затем отдать правленный csv обратно. Костыл а-ля как у меня в геоматрице, лучше так не делать, потом сложно вернуться в мир людей (((

Все верно, если мы сможем этот ключ выразить лексически, то потом сможем и в коде в виде условий в парсере.
Или всё таки подготовить книги руками, для загрузки в БД пока без условий и ИИ)))

Я имел в виду что этот набор ключей нужен для ручного редактирования — чтобы понятно было, что искать и удалять. Файлы подготовлены достаточно сильно, я обработчиком удалил много лишнего, например горизонтальные разделители, разделители шапки страниц, картинки. Это не проблема найти и зачистить, если известно что искать.

@iprst
Copy link
Collaborator Author

iprst commented May 13, 2023

Потестировал парсер как он сейчас выложен, согласно README, внёс в описание небольшие уточнения на тех моментах, где не удалось выполнить написанное с первого раза, по сути по невнимательности, но скорее всего этих ошибок можно избежать, если уточнить на более «табуретном» уровне.

Всё описанное работает. Парсер спарсил книги, постман ищет как предсказано. Не умею составлять более сложные запросы, поэтому пока просто искал по одному слову. Ищет, результаты мне нравятся. Показываемые строки (абзацы) понятны и думаю прямо в таком виде можно смело отдавать их во фронтенд, то есть не искать (во всяком случае сейчас) количество символов и тд.

Сами результаты в целом отличны. Возможно после подключения фронтенда можно будет поиграться с параматром score и ранкингом. В документации мантикоры:

Реализованные в настоящее время ранкеры являются:

proximity_bm25 , режим ранжирования по умолчанию, который использует и сочетает в себе как близость фразы, так и ранжирование BM25 — статистический режим ранжирования, который аналогичен большинству других полнотекстовых движков. Этот режим работает быстрее, но может привести к ухудшению качества запросов, содержащих более 1 ключевого слова.

количество слов, ранжирование по количеству вхождений ключевых слов. Этот ранкер вычисляет количество встречаемости ключевых слов для каждого поля, затем умножает их на веса полей и суммирует полученные значения.

в результате proximity возвращает необработанное значение близости фразы. Этот режим внутренне используется для эмуляции запросов SPH_MATCH_ALL.

И так далее.

Предлагаю сейчас вообще не дёргаться по поводу более углубленной конкретизации поиска, а загрузить базу, сделать простейший фронтенд и поиграться, многое будет найдено опытным путём. Самый эффективный способ проверить движок на адекватность — это написать с его помощью штук 20 внятных комментариев на ФКТ длиной 10-20 тысяч символов, используя в качестве аргументов 3-4 цитаты на какую-то очень чёткую тему.

@iprst
Copy link
Collaborator Author

iprst commented May 13, 2023

Создан новый issue в репозитории парсера книг, перейдём сразу к фронтенду:
Формирование выдачи результатов поиска

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants