База данных - набор сведений, хранящихся некоторым упорядоченным способом. Можно сравнить базу данных со шкафом, в котором хранятся документы. Иными словами, база данных - это хранилище данных. Сами по себе базы данных не представляли бы интереса, если бы не было систем управления базами данных (СУБД).
Система управления базами данных - это совокупность языковых и программных средств, которая осуществляет доступ к данным, позволяет их создавать, менять и удалять, обеспечивает безопасность данных и т.д. В общем СУБД - это система, позволяющая создавать базы данных и манипулировать сведениями из них. А осуществляет этот доступ к данным СУБД посредством специального языка - SQL.
Если ваша организация не находится в стадии экспоненциального роста, вероятно, не найдётся убедительных причин использовать БД, которая позволяет достаточно вольно обращаться с типами данных и нацелена на обработку огромных объёмов информации.
Вот признаки проектов, для которых идеально подойдут SQL-базы:
Первая реляционная база данных родилась в подразделении IBM Research в начале 70-х гг. В то время языки запросов основывались на сложной математической логике и не менее сложной нотации. Два свежеиспеченных кандидата наук, Дональд Чемберлин и Раймонд Бойс, впечатлились реляционной моделью данных, но при этом увидели, что используемый язык запросов будет препятствовать ее распространению. Они решили разработать новый язык запросов, который, по их словам, будет «более удобным для пользователей, не прошедших курс математики или компьютерного программирования».
В результате появился SQL, впервые представленный миру в 1974 году, и в следующие несколько десятилетий он станет очень популярным. Поскольку в отрасли ПО обосновались реляционные базы данных (например, System R, Ingres, DB2, Oracle, SQL Server, PostgreSQL, MySQL и многие другие), SQL широко распространился как язык взаимодействия с БД и стал общепринятым в экосистеме, которая становилась все более конкурентной.
С ростом сети Интернет разработчики ПО обнаружили, что реляционные базы данных не могут справиться с такой нагрузкой. Затем два новых интернет-гиганта совершили прорыв — разработали собственные распределенные нереляционные системы, предназначенные для решения проблемы с возрастающими объемами данных: MapReduce (публикация 2004 г.) и Bigtable (публикация 2006 г.) от компании Google и Dynamo (публикация 2007 г.) от компании Amazon. Упав на благодатную почву, опубликованные статьи дали хороший урожай нереляционных баз данных: Hadoop (на основе статьи по MapReduce, 2006 г.), Cassandra (авторы вдохновлялись статьями по Bigtable и Dynamo, 2008 г.), MongoDB (2009 г.) и др. Новые системы были написаны преимущественно с чистого листа, поэтому они тоже не использовали SQL, что привело к росту «движения NoSQL».
Творение компаний Google и Amazon распространилось, похоже, гораздо шире, чем предполагали сами авторы. И понятно, почему так случилось: NoSQL-системы были в новинку; они обещали масштабирование и мощь; казалось, что это — быстрый путь к успешной разработке. И тут начали вылезать проблемы.
Вскоре разработчики обнаружили, что отсутствие SQL на самом деле существенно ограничивает. У каждой базы данных NoSQL был собственный уникальный язык запросов, а это означало следующее: нужно было изучать больше языков (и обучать своих коллег); подключать эти базы данных к приложениям было сложнее, что заставляло писать тонны неустойчивого связующего кода; отсутствие сторонней экосистемы — а значит, компаниям приходилось разрабатывать собственные инструменты для визуализации и работы с БД.
Языки NoSQL только появились, поэтому их нельзя было назвать полными и завершенными: в реляционных БД, к примеру, многие годы работали над добавлением в SQL необходимых функций.
Разработчики ПО стали понемногу начали возвращаться к SQL.
NoSQL – коротко о главном NoSQL базы данных: понимаем суть
Термин NoSQL. Есть две трактовки: одна старая, другая новая. Оригинальная — это NoSQL, т.е., вообще, никакого SQL-а нет, а есть какой-то другой механизм, для работы с этой базой данных. И более новая трактовка — это «Not only SQL» — это не только SQL, т.е. может быть SQL, но есть что-то помимо.
Распределенная система не может одновременно обладать более чем двумя из следующих трех характеристик — это доступность (availability), согласованность (consistency) и устойчивость к разрывам сети (partition tolerance).
Список NoSQL-БД. Доступность — это если у нас есть распределенная система, и мы обращаемся на любой ее узел и гарантированно получаем ответ. Если мы запрашиваем какие-то данные, то можем получить устаревшие версии этих данных, но мы получим данные, а не ошибку, или мы могли бы не достучаться до этого сервера. Если мы получили данные, то система доступна.
В противоположность этому система может быть согласована. Что означает согласованность? Если мы на одном узле записали какие-то данные и спустя некоторое время на другом узле пытаемся прочитать эти данные, если система согласована, мы получим новую версию данных, которую мы записали в другом месте.
Минимальный интерфейс для такой базы данных состоит всего из 3-х операций — get, set и delete.
СУБД, специально предназначенная для хранения иерархических структур данных (документов). В основе документоориентированных СУБД лежат документные хранилища, имеющие структуру дерева. API для поиска позволяет находить по запросу документы и части документов. В отличие от хранилищ типа ключ-значение, выборка по запросу к документному хранилищу может содержать части большого количества документов без полной загрузки этих документов в оперативную память.
Их сильная сторона в способности хранить большое количество данных с большим количеством атрибутов. Они немного по-другому хранят данные, нежели, например, реляционные базы данных — реляционки хранят по строкам, т.е. все атрибуты одной строки лежат рядом. Эти делают наоборот, они хранят отдельно колонки. Есть файл — в нем хранятся все поля данной колонки из всех 3-х млрд. записей, хранятся все рядом. Соответственно, другая колонка хранится в другом файле. За счет этого они могут применять улучшенное сжатие за счет использования информации о типе данных колонки. Также это может ускорять запросы, если, нам, например, нужны 3 колонки из 300, то нам не обязательно грузить остальные 297.
Предназначены для обработки графов — набора вершин, соединенных ребрами. Например, социальные сети — это один большой граф. Дорожная сеть и прокладка маршрутов, рекомендация товаров.
Сила этих баз данных в том, что за счет своей специализации они могут эффективно выполнять всякие операции над графами, но также в силу той же специализации они не сильно распространены.
Вот свойства проектов, для которых подойдёт что-то из сферы NoSQL:
Главное правило проектирования структуры данных в NoSQL базах — она должна подчиняться требованиям приложения и быть максимально оптимизированной под наиболее частые запросы. Если платежи регулярно извлекаются вместе с заказом — имеет смысл их включать в общий объект, если же многие запросы работают только с платежами — значит, лучше их вынести в отдельную сущность.
Почему SQL одерживает верх над NoSQL, и к чему это приведет в будущем
Когда ваши данные по своей природе реляционны.
Когда невозможно заранее спроектировать модель использования (или лично вы не умеете проектировать).
Для создания реляционной БД необходимо вначале описать схему, в которой определим будут определены таблицы с колонками, типами данных колонок и отношениями между ними.
cursor.execute(""" CREATE TABLE Authors( id TEXT PRIMARY KEY UNIQUE NOT NULL, name TEXT, region TEXT, gender TEXT, age INTEGER, city TEXT, stage TEXT )""") cursor.execute(""" CREATE TABLE Texts( id INTEGER PRIMARY KEY UNIQUE NOT NULL, raw TEXT, lemm TEXT, url TEXT, datetime TEXT, author TEXT, title TEXT, stage TEXT, FOREIGN KEY (author) REFERENCES Authors (id) ON DELETE CASCADE ON UPDATE CASCADE )""") cursor.execute(""" CREATE TABLE Ethnonyms( id TEXT PRIMARY KEY UNIQUE NOT NULL )""") cursor.execute(""" CREATE TABLE Assessors( id TEXT PRIMARY KEY UNIQUE NOT NULL )""") cursor.execute(""" CREATE TABLE Ethnonyms_Texts( text_id INTEGER NOT NULL, ethnonym_id TEXT NOT NULL, PRIMARY KEY(ethnonym_id, text_id), FOREIGN KEY(ethnonym_id) REFERENCES Ethnonyms(id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY(text_id) REFERENCES Texts(id) ON DELETE CASCADE ON UPDATE CASCADE )""") cursor.execute(""" CREATE TABLE Assessors_Ethnonyms_Texts( text_id INTEGER NOT NULL, ethnonym_id TEXT NOT NULL, assessor_id TEXT NOT NULL, about_whole_nation_recoded INTEGER, encourage_aggression_meaning INTEGER, is_ethicity_aggressor_meaning INTEGER, is_ethicity_dangerous_meaning INTEGER, is_ethicity_superior_meaning INTEGER, opinion_about_ethnonym_recoded INTEGER, represent_ethicity_meaning INTEGER, FOREIGN KEY (text_id) REFERENCES Texts (id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (assessor_id) REFERENCES Assessors (id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (ethnonym_id) REFERENCES Ethnonyms (id) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (text_id, ethnonym_id, assessor_id) )""") cursor.execute(""" CREATE TABLE IF NOT EXISTS Assessors_Texts( text_id INTEGER NOT NULL, assessor_id TEXT NOT NULL, do_text_make_sense INTEGER, has_eth_conflict INTEGER, has_ethnonym INTEGER, has_pos_eth_interaction INTEGER, has_topic_culture INTEGER, has_topic_daily_routine INTEGER, has_topic_economics INTEGER, has_topic_ethicity INTEGER, has_topic_history INTEGER, has_topic_humour INTEGER, has_topic_migration INTEGER, has_topic_other INTEGER, has_topic_politics INTEGER, has_topic_religion INTEGER, has_topic_society INTEGER, is_text_neg INTEGER, is_text_positive INTEGER, FOREIGN KEY (text_id) REFERENCES Texts (id) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (assessor_id) REFERENCES Assessors (id) ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY (text_id, assessor_id) )""")
Для облегчения понимания:
А для тех, кто хочет окунуться в теории реляционных баз полностью — добро пожаловать на курс на Степике.
В результате получаем такую структуру Создано при помощи Dbeaver
Не требуется.
Не требуется.
### Импортируем библиотеку, соответствующую типу нашей базы данных import sqlite3 connection = sqlite3.connect('data/ethno.db') connection.execute("PRAGMA foreign_keys = ON") cursor = connection.cursor()
В конце необходимо будет выполнить connection.commit()
чтобы воплотить изменения и connection.close()
чтобы закрыть соединение.
mongodb://<dbuser>:<dbpassword>@ds024548.mlab.com:24548/hse
from pymongo import MongoClient import urllib.parse username = urllib.parse.quote_plus('student') password = urllib.parse.quote_plus('student1') connection_url = 'mongodb://{}:{}@ds024548.mlab.com:24548/hse'.format(username, password) client = MongoClient(connection_url) db = client.hse collection = db.test
import pandas as pd
df = pd.read_msgpack("data/ethno_df.msgpack")
Давайте сделаем выборку 10-и текстов из каждой системы хранения — SQLite, MongoDB и Pandas Dataframe. Отобразим всю информацию об авторах текстов, сам текст и время его написания. Причем, зададим условия, что нам нужны только лишь тексты пользователей из Москвы и СПб возраста старше 24 лет.
Базовый синтаксис такой
SELECT column1, column2 ..., columnN FROM table_name WHERE condition;
Подробнее здесь:
sql_query = ''' SELECT Texts.datetime, Texts.raw, Authors.region, Authors.age, Authors.gender FROM Texts LEFT JOIN Authors ON Authors.id = Texts.author WHERE Authors.region IN ('Москва', 'Санкт-Петербург') AND Authors.age >= 25 LIMIT 10 '''
cursor.execute(sql_query).fetchone() # fetchall() для всех записей
pd.read_sql(sql=sql_query, con=connection)
datetime | raw | region | age | gender | |
---|---|---|---|---|---|
0 | 2014-01-07 15:48:00 | Холокост с обратной стороны. Литовский политик... | Москва | 55 | Женщина |
1 | 2014-02-27 17:37:55 | Степан, бот ты все не угомонишься? как то вас ... | Санкт-Петербург | 36 | Мужчина |
2 | 2014-02-28 02:07:42 | Сергей, в Крыму уже находятся 76-я десантно-шт... | Санкт-Петербург | 28 | Мужчина |
3 | 2014-05-05 23:33:46 | Друзья всем советую смотреть <b>кыргыз</b> кин... | Москва | 1945 | None |
4 | 2014-06-06 15:38:00 | Инкубатор <b>пархатых</b> это Россия. По нашей... | Москва | 66 | Мужчина |
5 | 2014-12-02 15:48:04 | нормально все ходит. я через банк фк открытие ... | Санкт-Петербург | 28 | Мужчина |
6 | 2014-12-11 17:06:12 | В США полицейский застрелил безоружного <b>афр... | Москва | 33 | Женщина |
7 | 2015-01-12 21:06:57 | Симферополь.Памятник братьям Айвазовским - Ива... | Санкт-Петербург | 1945 | Мужчина |
8 | 2015-01-12 21:06:57 | Симферополь.Памятник братьям Айвазовским - Ива... | Санкт-Петербург | 1945 | Мужчина |
9 | 2015-01-15 16:31:18 | [[id65482402|Эдик], что ты несешь, дурашка? Ес... | Санкт-Петербург | 31 | Мужчина |
Операторы запросов: https://docs.mongodb.com/manual/reference/operator/query/
for doc in collection.find({ "author.region" : {"$in": ["Москва", "Санкт-Петербург"]}, "author.age": {"$gte": 25} }, {"author": 1, "datetime": 1, "raw": 1}).limit(10): print(doc)
# наишите сами
Удалим из базы записи, которые связаны с текстами про русских (это слово может быть прилагательным и указывать не только на этноним).
Да практически также, как и выборка, только SELECT
меняем на DELETE
и не указываем колонки.
sql_remove = ''' DELETE FROM Ethnonyms WHERE id = 'русский' ''' cursor.execute(sql_remove) # fetchall() для всех записей
cursor.execute("SELECT * FROM Ethnonyms_Texts WHERE ethnonym_id = 'русский'").fetchall() # connection.commit() # пока не будет выполнена эта строка, изменения не будут внесены.
Обращайте внимание на возможнось каскадного удаления (см. Руководство по проектированию реляционных баз данных. Каскадное удаление данных). Оно нужно, чтобы сохранить ссылочную целостность.
Ссылочная целостность может нарушиться) в следующих случаях:
Средства поддержания ссылочной целостности SQL позволяют обрабатывать указанные случаи.
collection.delete_many(query) # где query — это такой же запрос как с find # делать это мы не будет, посколько это сможет сделать только один человек
#
Есть два способа осуществить поиск по строке в SQLite. Первый — медленный, но простой. Второй — быстрый, но немного сложнее.
Начнём в первого — можно использовать оператор LIKE
, который найдёт строки, похожие на шаблон. Он регистрозависимый.
cursor.execute("SELECT * FROM Texts WHERE raw LIKE '%Вы че%'").fetchall()
Также в SQLite существует возможность выстрого полнотекстового поиска, но для этого надо немного поплясать с бубном.
Во-первых, необходимо создать виртуальную FTS-таблицу. Назовём её fts_table:
cursor.execute("CREATE VIRTUAL TABLE fts_table USING fts5 ( id, raw )");
Во-вторых, необходимо наполнить её значениями. В данном случае, мы просто скопируем в неё колонки id, raw из таблицы Texts:
cursor.execute("INSERT INTO fts_table SELECT id, raw FROM Texts");
И только затем мы можем производить поиск при помощи ключевого слова MATCH
:
cursor.execute("SELECT * FROM fts_table WHERE raw MATCH 'вы че'").fetchall()
Уффф... Это только начало, другие БД предоставляют более богатые возможности и более сложный синтаксис. Изучать его мы, конечно, не будем.
Тут всё немного проще благодаря оператору $text
. Единственная неочевидная вещь, которую требуется сделать — это создать текстовый индекс на том поле, по которому вы будете искать. Ну хоть не таблицу.
collection.create_index([('raw', 'text')])
repr(collection.find_one({ "$text" : { "$search" : "вы че" }})["raw"])
collection.find({ "$text" : { "$search" : "вы че" }}).count()
также существую обширные возможности для работы с текстом.
df[df.raw.str.contains("Вы че")].raw
df.raw.str.contains("Вы че").sum()
Сделайте следующие задания в каждой системе хранения данных:
sql_group = ''' SELECT Authors.region, COUNT(*) AS `num` FROM Texts LEFT JOIN Authors ON Authors.id = Texts.author WHERE Authors.region IN ('Москва', 'Санкт-Петербург') AND Authors.age >= 25 GROUP BY Authors.region '''
Существует немало других функций для работы с аггрегированными данными помимо COUNT.
connection.close()
Комментарии