![[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
no subject
Более поздний файл совершенно не обязательно более новый файл, поскольку акт загрузки файла и акт генерации fb2 никак в общем случае не связаны с актом творения текста. В базе либрусека мне попадались и менее очевидные сочетания, нежели "кто-то загрузил юболее старую версию с более нововй датой". Акт простановки связи replaces в общем случае творческая интерпретация информации в файле и сопутствующей (напр. внешнего относительно файла знания о сущности обновлений текста автором).
no subject
no subject
no subject
Затем что там записей будет в тысячи раз меньше.
no subject