comics_sql

Простой способ создать базу данных персонажей Marvel с использованием SQL and Javascript

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

Специализация «Frontend-разработчик»
Идет набор в группу 5900₽ в месяц

В этой статье я объясню как создать базу данных на основе комиксов Marvel (или DC), используя Википедию, Javascript и SQL. Мы создадим гибкий инструмент, который позволит вам создавать различные таблицы для использования в ваших собственных проектах — идеи, которые я объясню здесь, могут быть легко использованы и в других областях. Эта статья для тех, у кого не хватает времени для изучения сложного синтаксиса модифицированного SQL, который используется в системе Вики, но кто хотел бы все равно поработать с данными оттуда.

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

Визуализация вселенных Marvel & DC: https://heberleh.github.io/comics-universe/

План действий

Идея состоит в том, чтобы сделать следующие шаги и получить желаемую базу данных:

  1. Запрос таблиц с Wikidata и экспорт их в .json формате 
  2. Создание базы данных с помощью Alasql и загрузка туда данных из json файлов
  3. Использование созданной базы данных через  SQL запросы

1. Извлечение данных из Википедии

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

Там вы увидите что-то подобное (по этой же ссылке можно найти больше информации о построении запросов):


SELECT ?name ?gender ?genderLabel
  WHERE{
      ?name wdt:P31 wd:Q1114461;
          wdt:P1080 wd:Q931597.
      ?name wdt:P21 ?gender.
      SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

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

Для начала попробуйте ввести wdt:<Ctrl+Space>. Появится окошко помощи. Попробуйте добавить instance of. Вы увидите, что код для “instance of” — это wdt:P31. Используя такой же подход, вы можете узнать код для значения (value), написав wd:<Ctrl+Space> (без ‘t’ в этот раз) и comic character. Вуаля, вы получили код — wd:Q1114461.

<Ctrl+Space> открывает окно подсказок

Хорошо, Генри, но я без понятия что мы можем использовать, и у меня нет времени изучать язык Википедии… и я понимаю! Так что, чтобы обойти это препятствие, мы откроем эту страницу. В Вики код Q841372 соответсвует Джаггернауту. Теперь посмотрим какая информация доступна для характеристики comic character. Наведите указатель мыши на объекты в части Statements. Например, если вы наведете курсор на текст “instance of”, то вы получите код P31, который мы можем указать через wdt.

Анализ Данных: курс-тренажер по SQL
Идет набор в группу 1 600₽ в месяц

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

Ссылку на Wikidata можно найти на панели слева

Перейдите по ссылке и вы увидите все характеристики этого объекта. Например, мы можем получить вес, используя wdt:P2067, и множество других атрибутов, которые свойственны металлам.

У каждого объекта в Wikidata определены разные свойства. Всплывающая подсказка покажет ID каждой характеристики.

Теперь, когда мы разобрались с Wikidata, нам нужно:

  1. Создать запрос на интересующую нас характеристику
  2. Выгрузить результат в формате .json
  3. Всегда отслеживать ID (URL объекта в Wikidata) и ярлыки (labels)

Например, я создал один запрос на характеристику “пол”. Один запрос на “род деятельности” и так далее. Результатом будет папка с некоторым количеством .json файлов, которые я загружу в мою базу данных, сформированную из многих таблиц. Но вместо этого можно создать один единственный запрос для всей этой информации. В моем случае, я хочу сделать гибкий запрос, чтобы я мог выполнять такие команды как JOIN, LEFT JOIN  и SELECT, чтобы получать различные таблицы.

На самом деле, вместо того, чтобы получить персонажей только из вселенной Marvel, я убрал этот фильтр и получил полную базу данных вымышленных персонажей (не только персонажей комиксов — по какой-то причине такой запрос не срабатывал для Капитана Америки). Так что в моих .json файлах можно найти и Marvel, и DC, и других. Эти файлы можно найти на моей странице на GitHub. А теперь я покажу как я использовал их для простой SQL базы данных на Javascript.

Как я упомянул в предыдущем абзаце, мой запрос был сделан на класс “Fictional Characters” и его подклассы. Я также сделал запрос на партнеров и супругов, используя |, чтобы определить два wdt:


SELECT DISTINCT ?char ?partner  ?partnerLabel
WHERE
{
	?char wdt:P31/wdt:P279* wd:Q95074. # instande of Fictional Character and any sub-class
    	?char wdt:P451|wdt:P26 ?partner  # partner|spouse
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

Обратите внимание, что в коде выше я больше не фильтрую по принадлежности к Marvel. Как создавать более сложные запросы можно посмотреть на сайте Wikidata. Другой хороший вариант — это кнопка “Help” на странице Wikidata Query Service, где вы сможете найти примеры и пояснения.

2. Создание SQL базы данных на Javascript

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

Теперь мы применим SELECT на каждый .json файл и добавим данные в новую таблицу для простоты доступа. Для статьи я упрощу мой код и он будет содержать только две таблицы (полную версию вы можете найти здесь). Выглядеть это будет так: 

// Partial code - check my github to get the complete one
import alasql from 'alasql'
const character = require('../dataset/character.json');
const abilities = require('../dataset/abilities.json');
const fictionalUniverse = require('../dataset/fictionalUniverse.json');

function MarvelDB(){

    // Our jsons and table names
    let tables = [
        {name: 'abilities', data: abilities},
        {name: 'character', data: character}
    ]

    // Create database
    let db = new alasql.Database()

    // Only characters registered in the Marvel Universe
    db.exec('CREATE TABLE fictionalUniverse')
    db.exec('INSERT INTO fictionalUniverse\
                SELECT char FROM ? \
                WHERE fictionalUniverseLabel LIKE "Marvel Universe"', [fictionalUniverse])

    // For each Json in 'tables', create table
    tables.forEach(table => {
        // Creates temporary table (Should not be necessary, 
        // but because of bugs caused by nesting INSERT INTO with SELECT WHERE IN,)
        // I kept it like this:
        db.exec(`CREATE TABLE aux_${table.name}`);
        db.exec(`INSERT INTO aux_${table.name} SELECT * FROM ?`, [table.data]);
        let filtered_data = db.exec(`SELECT * FROM aux_${table.name}\
                                        WHERE aux_${table.name}.char IN\
                                        (SELECT char FROM fictionalUniverse)`);

        // Then when can create our table
        db.exec(`CREATE TABLE ${table.name}`);
        db.exec(`INSERT INTO ${table.name} SELECT * FROM ?`, [filtered_data]);

        // and delete the temporary one
        db.exec(`DROP TABLE  aux_${table.name}`);
    })

    // Drop fictionalUniverse table -> character table contains the same elements
    db.exec('DROP TABLE fictionalUniverse')

    return db
}

Готово. Теперь мы можем вызывать нашу базу данных let mydb = MarvelDB() и работать с ней через SQL команды, например: mydb.exec(‘SELECT DISTINCT abilityLabel from abilities’).

Специализация Full-stack веб-разработчик на Python
Идет набор в группу 5 900₽ в месяц

3. Финальные строки кода и использование БД

Я сделал несколько тестов, чтобы проверить, что все работает. К тому же, эти тесты показывают варианты использования нашей базы данных. Если вы не очень знакомы с тестированием, то вы можете оставить в коде, приведенном ниже, только let result = this.db.exec(…) и console.table(result), и проигнорировать все остальное.

// Unit test
describe('Select Queries', function() {
beforeEach(() => this.db = marvelDB())
it('Name of the only agender with registered abilities', () => {
let result = this.db.exec(
'SELECT DISTINCT character.charLabel AS name\
          FROM character JOIN gender ON character.char = gender.char\
          JOIN abilities ON character.char = abilities.char\
          WHERE gender.genderLabel LIKE "agender"');
//console.table(result);
expect(result[0].name).to.equal("Phoenix Force")
  })
})

Вышеприведенная команда SELECT возвращает колонку charLabel и переименовывает ее в name. Этот код также объединяет таблицы с персонажем, полом и способностями, удостоверившись, что эта новая запись сохранила верный ID персонажа. Ну и, наконец, наши данные фильтруются по выбранному полу agender. Больше примеров использования этой базы данных вы можете найти на GitHub — и не забудьте поставить звездочку этому репозиторию. 🙂

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

Визуализация миров Marvel & DC: https://heberleh.github.io/comics-universe/

Оригинал: Create a Marvel Database with SQL and Javascript, the easy way

Перевод: Ухарова Елена

Поделиться:
Опубликовано в рубрике Веб-разработка, Переводные материалыTagged , ,

SkillFactory.Рассылка