Заметки по поводу схемы ФЗР

Схема базы данных Фроша-Загорского-Радкевичюте (ФЗР-схема) разработана с целью упростить коллективную международную работу над текстами, в первую очередь способствующими развитию теоретического мышления. Детальное описание схемы находится в следующих статьях:

Сама схема, комментарии к которой описаны ниже, находится в этом репозиторииopen in new window. Надеемся, что следующие размышления могут быть полезны, для поиска путей развития ФЗР-схемы.

1. Стандарты оформления схемы базы данных

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

В качестве стандарта наименований для ФЗР предлагаем следующее:

1. Название всех объектов базы данных дается на Эсперанто.

2. Для идентификаторов используется стиль upper_snake_case: все символы в нижнем регистре, для разделителей используется символ подчеркивания _.

Такой подход позволит избавится от кавычек в коде приложения и скриптах.

Пример, сейчас таблица создается так:

CREATE TABLE Lingvoj
(
    ISO 639-3      char(3) PRIMARY KEY,
    Nomo originala text NOT NULL,
    Nomo           text,
    Familio        int  NOT NULL,
    ISO 639-1      char(2),
    CONSTRAINT Lingvoj_Lingva_familioj_FK FOREIGN KEY (Familio) REFERENCES Lingva familioj (Kodo)
);

А так в соответствии с этим правилом:

CREATE TABLE lingvoj
(
    iso_639_3      char(3) PRIMARY KEY,
    nomo_originala text NOT NULL,
    nomo           text,
    familio        int  NOT NULL,
    iso_639_1      char(2),
    CONSTRAINT lingvoj_lingva_familioj_fk FOREIGN KEY (familio) REFERENCES lingva_familioj (Kodo)
);

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

Пример, сейчас таблица создается так:

CREATE TABLE Libroj - nomoj
(
    Libro  uuid        NOT NULL,
    Lingvo varchar(3)  NOT NULL,
    Nomo   text        NOT NULL,
    Uzanto varchar(64) NOT NULL DEFAULT user,
    Tempo  timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT Libroj_nomoj_pk PRIMARY KEY (Libro, Lingvo),
    CONSTRAINT Libroj_nomoj_Libroj_FK FOREIGN KEY (Libro) REFERENCES Libroj (Kodo),
    CONSTRAINT Libroj_nomoj_Lingvoj_FK FOREIGN KEY (Lingvo) REFERENCES Lingvoj (ISO 639-3)
);

А так в соответствии с этим правилом:

CREATE TABLE libro_nomo
(
    libro  uuid        NOT NULL,
    lingvo varchar(3)  NOT NULL,
    nomo   text        NOT NULL,
    uzanto varchar(64) NOT NULL DEFAULT user,
    tempo  timestamptz NOT NULL DEFAULT now(),
    CONSTRAINT libro_nomo_pk PRIMARY KEY (libro, lingvo),
    CONSTRAINT libro_nomo_libroj_fk FOREIGN KEY (libro) REFERENCES libro (kodo),
    CONSTRAINT libro_nomo_lingvoj_fk FOREIGN KEY (lingvo) REFERENCES lingvo (iso_639_3)
);

4. Именование первичных и внешних ключей должно подчинятся следующим правилам:

  • Первичные ключи — [название таблицы]_[список полей ключа]_pk
  • Внешние ключи — [название таблицы]_[список полей ключа]_pk

Пример, сейчас таблица создается так:

CREATE TABLE Paragrafoj - notoj
(
    Paragrafo   uuid        NOT NULL,
    Aŭtora      bool        NOT NULL,
    Kodo_de_Div text        NOT NULL,
    Uzanto      varchar(64) NOT NULL DEFAULT user,
    Tempo       timestamptz NOT NULL DEFAULT now(),
    Fonto       uuid        NOT NULL,
    CONSTRAINT Paragrafoj_notoj_Paragrafoj_FK FOREIGN KEY (Paragrafo) REFERENCES Paragrafoj (Kodo),
    CONSTRAINT Paragrafoj_notoj_Paragrafoj_FK1 FOREIGN KEY (Fonto) REFERENCES Paragrafoj (Kodo)
);

А так в соответствии с этим правилом:

CREATE TABLE paragrafo_noto
(
    paragrafo   uuid        NOT NULL,
    aŭtora      bool        NOT NULL,
    kodo_de_div text        NOT NULL,
    uzanto      varchar(64) NOT NULL DEFAULT user,
    tempo       timestamptz NOT NULL DEFAULT now(),
    fonto       uuid        NOT NULL,
    CONSTRAINT paragrafo_noto_paragrafo_fk FOREIGN KEY (paragrafo) REFERENCES paragrafo (kodo),
    CONSTRAINT paragrafo_noto_fonto_fk FOREIGN KEY (fonto) REFERENCES paragrafo (kodo)
);

5. Ко всем таблицам и к каждому полю таблицы должны быть обязательные комментарии на Эсперанто. Для полей с внешними ключами рекомендовано указание таблицы на которую ссылается поле.

Комментарии позволяют быстрее разбираться в схеме и будут способствовать изучению языка.

Пример добавления комментариев:

COMMENT ON TABLE public.lingvo IS 'Listo de lingvoj';

COMMENT ON COLUMN public.lingvo.nomo_originala IS 'Nomo en originala lingvo';
COMMENT ON COLUMN public.lingvo.nomo IS 'Nomo en Esperanto';
COMMENT ON COLUMN public.lingvo.familio IS 'Lingva familio, ligo al lingva_familio (kodo)';

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

7. Кроме самой схемы, полезно было бы полноценное текстовое описание схемы. Вероятно, так же на Эсперанто. Многие тонкие моменты, например, то каким способом храниться разрыв страницы внутри абзаца, затруднительно описать в комментариях к полям. По сути, нужна полноценная документация. В этой документации так же могут находится примеры запросов (select) с комментариями.

2. Использование идентификаторов из Wikidata

Для объединения разных баз данных потребуется наличие одинаковых идентификаторов для авторов, работ и, возможно, каких-то ещё. Эта проблема похожа на ту которая решена справочником языков, чтобы каждая группа не делала свой справочник, используется международный стандарт ISO-639open in new window. Такой же подход можно попробовать использовать для людей и работ. Один из вариантов откуда взять такой справочник — wikidata.orgopen in new window. Каждый человек и работа в wikidata имеет свой идентификатор, например:

Для использования идентификатора можно добавить в таблицы авторов и работ необязательные поля:

CREATE TABLE "Aŭtoroj"
(
    "Kodo"                    uuid        NOT NULL DEFAULT uuid_generate_v4(),
    "Nomo originalo - lingvo" varchar(3)  NOT NULL,
    ...
    wikidata_kodo int  NULL,
);

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

CREATE TABLE ekstera_sistemo
(
    kodo   uuid          NOT NULL DEFAULT uuid_generate_v4()  primary key,
    nomo   varchar(100)  NOT NULL,
    ligilo varchar(100)  NOT NULL
);

COMMENT ON TABLE public.ekstera_sistemo IS 'Listo de eksteraj sistemoj';
COMMENT ON COLUMN public.ekstera_sistemo.kodo IS 'Kodo de ekstera sistemo';
COMMENT ON COLUMN public.ekstera_sistemo.nomo IS 'Nomo de ekstera sistemo';
COMMENT ON COLUMN public.ekstera_sistemo.ligilo IS 'Ligo al ekstera sistemo';

INSERT INTO ekstera_sistemo(nomo, ligilo) VALUES('Wikidata', 'https://www.wikidata.org/');

CREATE TABLE interna_objekto
(
    kodo   uuid          NOT NULL DEFAULT uuid_generate_v4() primary key,
    tablo varchar(100)   NOT NULL
);

COMMENT ON TABLE public.interna_objekto IS 'Listo de internaj objektoj';
COMMENT ON COLUMN public.interna_objekto.kodo IS 'Kodo de interna objekto';
COMMENT ON COLUMN public.interna_objekto.tablo IS 'Tablo de interna objekto';

INSERT INTO interna_objekto(tablo) VALUES('aŭtoro');

CREATE TABLE kongrua_kodo
(
    interna_kodo uuid NOT NULL,
    interna_objekto uuid NOT NULL,
    ekstera_kodo uuid NOT NULL,
    ekstera_sistemo uuid NOT NULL,
    CONSTRAINT kongrua_kodo_interna_objekto FOREIGN KEY (interna_objekto) REFERENCES interna_objekto (kodo),
    CONSTRAINT kongrua_kodo_ekstera_sistemo FOREIGN KEY (ekstera_sistemo) REFERENCES ekstera_sistemo (kodo)
);

COMMENT ...

Содержимое Wikidata наполняется сообществом, поэтому добавить туда новых авторов и работы может любой человек.

3. Использование html и css

Сейчас схема подразумевает использование элементов основанных на html в таблицах Dizajnoj, Dizajnoj - elementoj, Paragrafoj, в полях Klaso и Etikedo, а, возможно, и в Interno. Следующие цитаты из Что не так с текстологией и как исправить ситуациюopen in new window:

Абзац имеет собственный код("Kodo"), принадлежность к работе (код другой таблицы в "Laboro"), маркировку для гипертекста "Etikedo", класс для гипертекста "Klaso" и, главное, текстовое содержание "Interno"

Если же издатели отметили все абзацы цитат шрифтом несколько меньшего размера, но авторская рукопись не даёт примеров такого приёма, то абзацы цитат подлежат пометке «», что даст в таблице абзацев Etikedo = p Klaso = Citato. В этом случае правила оформления цитат должны быть прописаны в двух таблицах, название которых включает «Dizajnoj». В одной таблице указывается применимость правил (элемент p и классом Citato), в другой его код связывается с отдельными правилами оформления.

Стоит рассмотреть возможность отказаться от наследия связанного с html, в частности поля Klaso и Etikedo можно объединить в одно поле. В целом, лучше ориентироваться на логическую разметку, исключить в данных разметку связанную с форматированием. В этом смысле, таблица Dizajnoj может остаться, но получить другое назначение, например "вид параграфа" или "тип параграфа", которые могут означать обычный абзац, заголовок, изображение и др.

Внутри Interno тоже лучше исключить теги html, а использовать описанный язык облегченной разметки, например, для выделения жирным и курсивом. Детальнее преимущества такого подхода описаны в статье Технические аспекты цифровой текстологииopen in new window.

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

4. Версионирование параграфов

Полезна была бы возможность хранения предыдущих версий текста параграфа. Это может быть нужно для проверки работы участников при коллективной вычитке. Так работает Wikisource, любой участник может посмотреть всю историю изменений текста на странице: кто, что и когда изменял (примерopen in new window). Без этого затруднительно проверить правильность работы когда к вычитке подключается много участников.

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

5. Структура текста

Сейчас текст представлен в виде линейной последовательности параграфов (таблицы Paragrafoj и Paragrafoj - ĉenoj), кроме того могут быть связанные линейные последовательности примечаний (таблица Paragrafoj - notoj).

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

В общем случае абзацы должны быть пронумерованы и каким-то образом должен быть помечен тип абзаца — цитата, авторский текст, подпись под иллюстрацией, заголовок главы, заголовок работы и прочее. (Что не так с текстологией и как исправить ситуациюopen in new window)

Получается такая структура:

Блок
|
Блок ---- Примечание1
|
Блок ---- Примечание2
|         |      
Блок      Примечание2

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

Заголовок1
|
|------ Подзаголовок1
|      |---------------- Цитата
|                        |---------- Параграф 
|------ Подзаголовок2    |---------- Параграф
        |------ Параграф
        |------ Цитата       
                |------ Параграф
                |------ Параграф

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

От первых абзацев многоабзацных примечаний первый абзац авторского текста отличается тем, что для него невозможно найти (в таблице абзацев-примечаний) исходного абзаца. То есть первый абзац авторского текста не является примечанием для какого-либо другого абзаца. (Что не так с текстологией и как исправить ситуациюopen in new window)

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

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

Последниее изменение: