![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Про флибусту
Скачавши очередное (декабрьское) обновление флибусты, решил подумать о том, как бы себе сделать правильную искалку по ее метаинформации. На основании того, что я знаю о XML-схеме fb2-файлов и о том как устроены индексные (inpx) файлы флибусты. (ну и о том что флибустьеры не правят метаинфомрацию в файлах, поэтому корректная метаинформация содержится (если содержится) только в inp-файлах.
Ну то есть я знаю что у MyHomeLib схема базы кривая, ее какой-то девопс дизайнил, который не то что Дейта - Граббера не читал.
Ну для начала взял pgmodeller и нарисовал ER-диаграмму каталога библиотеки fb2-файлов. Из чисто флибустовских сущностей добавил туда только понятие архива. В смысле того zip-файла в котором в скачанном из торрентов мирроре лежит нужный f2.
Получилось 10 таблиц. Сущностей в принципе не так уж много
- book
- author (он же translator)
- sequence
- lang (классификатор для полей lang и srclang в таблице book)
- genre
Но везде же отношения m:n и нужны развязывающие таблички. А в табличке устанавливающей соответствие между книгой и серией еще и содержательное поле number лежит. И ведь на него даже NOT NULL не повесишь, я же знаю что полно есть в архиве книг у которых серия без номера.
Вообще я чувствую, что над жанрами еще табличка транзитивного замыкания нужна чтобы из них дерево выстроить. Но поскольку fb2-шной концепции жанров я никогда не понимал (и подозреваю что большая часть оцифровщиков тоже и жанры они в fb2-файлах ставили от балды) занимтаься этим мне лень.
Вот теперь думаю - писать парсилку inp-файлов в эту схему в sqlite, или уж сразу постгрес использовать. (и импортить туда весь текст fb2 на предмет организации полнотекстового поиска).
Для интересующихся сдизайненную схему положу под кат:
CREATE TABLE lang ( lang_code char(3) NOT NULL, lang_name text NOT NULL, CONSTRAINT lang_pk PRIMARY KEY (lang_code) ); CREATE TABLE archive ( archive_id serial NOT NULL, archive_name text NOT NULL, CONSTRAINT archive_pk PRIMARY KEY (archive_id) ); CREATE TABLE book ( book_id int8 NOT NULL, title text NOT NULL, file text NOT NULL, deleted boolean NOT NULL DEFAULT false, writedate datetime, lang char(3), srclang char(3), archive smallint NOT NULL, CONSTRAINT book_pk PRIMARY KEY (book_id), FOREIGN KEY (lang) REFERENCES lang(lang_code), FOREIGN KEY (srclang) REFERENCES lang(lang_code), FOREIGN KEY (archive) REFERENCES archive(archive_id) ); CREATE TABLE author ( author_id int4 NOT NULL, first_name text, middle_name text, last_name text, nickname text, CONSTRAINT author_pk PRIMARY KEY (author_id) ); CREATE TABLE seq ( sequence_id int4 NOT NULL, name text NOT NULL, CONSTRAINT seq_pk PRIMARY KEY (sequence_id) ); CREATE TABLE replaces ( old_book_id int8 NOT NULL, new_book_id int8 NOT NULL, CONSTRAINT replaces_pk PRIMARY KEY (old_book_id,new_book_id), FOREIGN KEY (old_book_id) REFERENCES book(book_id), FOREIGN KEY (new_book_id) REFERENCES book(book_id) ); CREATE TABLE book_author ( book_id int8 NOT NULL, author_id int4 NOT NULL, CONSTRAINT book_author_pk PRIMARY KEY (book_id,author_id), FOREIGN KEY (book_id) REFERENCES book(book_id), FOREIGN KEY (author_id) REFERENCES author(author_id) ); CREATE TABLE book_translator ( book_id int8 NOT NULL, translator_id int4 NOT NULL, CONSTRAINT book_translator_pk PRIMARY KEY (book_id,translator_id), FOREIGN KEY (book_id) REFERENCES book(book_id), FOREIGN KEY (translator_id) REFERENCES author(author_id) ); CREATE TABLE book_seq ( book_id int8 NOT NULL, sequence_id int4 NOT NULL, sequence_number int4, CONSTRAINT book_seq_pk PRIMARY KEY (book_id,sequence_id), FOREIGN KEY (book_id) REFERENCES book(book_id), FOREIGN KEY (sequence_id) REFERENCES seq(sequence_id) ); CREATE TABLE genre ( genre_id varchar(20) NOT NULL, genre_name text NOT NULL, CONSTRAINT genre_pk PRIMARY KEY (genre_id) ); CREATE TABLE book_genre ( book_id int8 NOT NULL, genre_id varchar(20) NOT NULL, CONSTRAINT book_genre_pk PRIMARY KEY (book_id,genre_id), FOREIGN KEY (book_id) REFERENCES book(book_id), FOREIGN KEY (genre_id) REFERENCES genre(genre_id) );
Что характерно, пока я причесывал этот SQL скрипт так, чтобы его сожрал sqlite, его объем сократился в 2.5 раза, а из содержательной информации потерялись только имена констрейнтов внешних ключей (и то можно было бы сохранить).
no subject
Ну насчет того что "в принципе содержаться не может", не согласен. вот этот мой скрипт кроме fb2 поддерживает pdf, djvu и epub. И все эти форматы вполне умеют хранить в себе метаинформацию. Правда почему то ни в Doublin Core, ни в адобовских спецификациях понятие "серии" как в fb2 не предусмотрено. Поэтому связи между файлами действительно описать сложно.
Вообще на мой взгяд в библиотеке, по моему кроме алфавитного каталога по авторам и заглавиям и тематического каталога нужны еще региональный каталог (как у нас в факультетской библиотеке было). темпоральный каталог, причем по двум осям - период описываемый в книге и время ее написания, и каталог упоминаемых персоналий.
no subject
Под связью между файлами я имел в виду что-то вида: "этот файл является улучшенной копией того файла", серии-же конструкция искусственная и весьма спорно, нужно ли для их поддержки городить отдельный огород.
Я долго размышлял насчет каталогов и пришел к выводу, что вот это вот все (алфавитный, тематический и прочее) нужно было в первую очередь для бумажных библиотек, чтобы однозначно расставлять книги по полкам и чтобы было возможно хоть что-то там найти. Для библиотек электронных это все неактуально, поиск лучше чем любой каталог.
Даже тематический каталог сильно подробный не нужен. Это в бумажной библиотеке нужно с помощью каталога отобрать считанные единицы книг, т.к. ни один библиотекарь не потащит вам для посмотреть пару сотен томов. В электронной-же библиотеке это совершенно не проблема.
no subject
Вот для такой связи между файлами я в вышепреведетнной схеме БД завел таблицу "replaces".
no subject
no subject
Более поздний файл совершенно не обязательно более новый файл, поскольку акт загрузки файла и акт генерации fb2 никак в общем случае не связаны с актом творения текста. В базе либрусека мне попадались и менее очевидные сочетания, нежели "кто-то загрузил юболее старую версию с более нововй датой". Акт простановки связи replaces в общем случае творческая интерпретация информации в файле и сопутствующей (напр. внешнего относительно файла знания о сущности обновлений текста автором).
no subject
no subject
no subject
Затем что там записей будет в тысячи раз меньше.
no subject