В интернете есть мол таблицы и они работают как трейнеры, но! куда их вводить и как пользоваться, объясните пожалуйста кто знает. 4 года
1)нужна сама программа Cheat Engine
2)скачиваешь таблицу и жмакаешь на нее, открывается CE
3)запускаешь игру и сворачиваешь, в CE нажимаешь на компьютер слева вверху и выбираешь процесс игры, потом нажимаешь да. 4) тыкаешь на квадратики для активации
а туториал тебе зачем?
Запускаешь игру и загружаешь таблицу в Cheat Engine. Далее правишь значения или кнопочки нажимаешь.
но как таблицу загрузить в Cheat Engine
Я скачал таблицу для игры и как её теперь использовать? вот инструкция- Процесс запуска:
1. Запустить Cheat Engine, «Load» и выбрать таблицу
2. «Select a process to open», выбрать нужный процесс. Выбрать нужную опцию, поставить крест. но не понятно где берётся этот «Load» и где выбирать таблицу
1 год
ЗАпускаешь прогу. ЗАпускаешь игру. Выбираешь в чит енждине процесс игры. Потом тянешь мышкой скачанную таблицу прямо на окно чит енджин. Подтверждаешь загрузку таблицы.
чел разархивируй архив. rar, потом в Cheat Engine слева вверху нажимаешь на File, там Load и т.
просто открыть таблицу и выбрать процесс
Vlad Bazaev6 февраля 2020 в 22:08 #
PSih20976 февраля 2020 в 22:34 #
Vlad Bazaev
скрин окна выложи.
Vlad Bazaev7 февраля 2020 в 12:11 #
PSih20977 февраля 2020 в 14:24 #
Таблица позволяет редактировать параметры поселенцев:
- God Mode (Режим бога)
- Mood (Настроение)
- Work (Работа)
- Adult (Возраст)
- Health (Здоровье)
- Food (Голод)
- Water (Жажда)
- Sleep (Сон)
- Warmth (Тепло)
- Cleanliness (Чистота)
- Bathroom (Нужда)
- Social (Общение)
- Fun (Веселье)
Редактирование и заморозка параметров не вызывает проблем с игровым процессом и не лишает возможности с сохранениями(какие есть при активации функций в таблице от FluffyWafflesIX). Работоспособность проверена на версии игры 0. 238
- Запустить Cheat Engine, «Load» и выбрать таблицу
- «Select a process to open», выбрать нужный процесс.
- Выбрать нужную опцию, поставить крест.
Общее описание
Актуальная версия apache hive(2. 0) представляет собой продвинутый фреймворк, который может работать не только поверх фреймворка Map/Reduce, но и поверх Spark(про спарк у нас будут отдельные статьи в цикле), а также Apache Tez.
В отличие от трейнеров, таблицы для чит-движка не являются самостоятельными программами. Использовать. ct файлы, вам нужно установить программу под названием Чит Двигатель. Если вы уже установили программу. вот пошаговое руководство по использованию файла. CT:
После того, как таблица загружена, если есть скрипт, просто проверьте его. Если у вас есть указатели, измените их, дважды щелкнув их значения, и зафиксируйте их, активировав назначенный им флажок. ALT+TAB вернитесь в игру и получайте удовольствие. Важно!: Вы можете использовать эту программу только для читов в одиночном или автономном режиме.
Привет, Хабр! Мы продолжаем наш цикл статьей, посвященный инструментам и методам анализа данных. Следующие 2 статьи нашего цикла будут посвящены Hive — инструменту для любителей SQL. В предыдущих статьях мы рассматривали парадигму MapReduce, и приемы и стратегии работы с ней. Возможно многим читателям некоторые решения задач при помощи MapReduce показались несколько громоздкими. Действительно, спустя почти 50 лет после изобретения SQL, кажется довольно странным писать больше одной строчки кода для решения задач вроде «посчитай мне сумму транзакций в разбивке по регионам».
С другой стороны, классические СУБД, такие как Postgres, MySQL или Oracle не имеют такой гибкости в масштабировании при обработке больших массивов данных и при достижении объема большего дальнейшая поддержка становится большой головоной болью.
Собственно, Apache Hive был придуман для того чтобы объединить два этих достоинства:
- Масштабируемость MapReduce
- Удобство использования SQL для выборок из данных.
Под катом мы расскажем каким образом это достигается, каким образом начать работать с Hive, и какие есть ограничения на его применения.
О популярной библиотеке SQLAlchemy для работы с разными СУБД из Python было написано довольно много статей. Предлагаю вашему вниманию обзор и сравнение запросов с использованием ORM и SQL подходов. Данное руководство будет интересно прежде всего начинающим разработчикам, поскольку позволяет быстро окунуться в создание и работу с SQLAlchemy, поскольку документация от разработчика SQLAlchemy на мой скромный взгляд тяжела для чтения.
Немного о себе: я также начинающий Python разработчик, прохожу обучение по курсу «Python разработчик». Данный материал был составлен не в результате ДЗ, а в порядке саморазвития. Мой код может быть достаточно наивным, в связи с чем прошу не стесняться и свои замечания оставлять в комментариях. Если я вас еще не напугал, прошу под кат 🙂
Мы с вами разберем практический пример нормализации плоской таблицы, содержащей дублирующиеся данные, до состояния 3НФ (третьей нормальной формы).
Из вот такой таблицы:
Таблица с данными
сделаем вот такую БД:
Схема связей БД
Для нетерпеливых: код, готовый к запуску находится в этом репозитории. Интерактивная схема БД здесь. Шпаргалка по составлению ORM запросов находится в конце статьи.
Договоримся, что в тексте статьи мы будем использовать слово «Таблица» вместо «Отношение», и слово «Поле» вместо «Аттрибута». По заданию нам надо таблицу с музыкальными файлами поместить в БД, при этом устранив избыточность данных. В исходной таблице (формат CSV) имеются следующие поля (track, genre, musician, album, length, album_year, collection, collection_year). Связи между ними такие:
- каждый музыкант может петь в нескольких жанрах, как и в одном жанре могут выступать несколько музыкантов (отношение многие ко многим)
- в создании альбома могут участвовать один или несколько музыкантов (отношение многие ко многим)
- трек принадлежит только одному альбому (отношение один ко многим)
- треки могут в ходить в состав нескольких сборников (отношение многие ко многим)
- трек может не входить ни в одну в коллекцию.
Для упрощения предположим что названия жанров, имена музыкантов, названия альбомов и коллекций не повторяются. Названия треков могут повторяться. В БД мы запроектировали 8 таблиц:
- genres (жанры)
- genres_musicians (промежуточная таблица)
- musicians (музыканты)
- albums_musicians (промежуточная таблица)
- albums (альбомы)
- tracks (треки)
- collections_tracks (промежуточная таблица)
- collections (коллекции)
* данная схема тестовая, взята из одного из ДЗ, в ней есть некоторые недостатки — например нет связи треков с музыкантом, а также трека с жанром. Но для обучения это несущественно, и мы опустим этот недостаток.
Для начала разберем процесс запуска таблицы:
- Запускаем FIFA 18
- Запускаем Cheat Engine
- После запуска программы нажать на «Load» (Ctrl+O) и выбрать таблицу. (1)
- Затем выбрать процесс «Select a process to open», выбрать FIFA 18 (2)
S Из-за несовпадения версий Cheat Engine могут всплывать окна, любые всплывающие окна лучше закрывать. Открываем программу и ставим крестик на «ActivateItFirst»Нам открывается большой список наших возможностей в редактировании. TheJourneyРедактирование режима истории Хантера. Unlock «Edit Player» in career menuОткрывает меню «Изменить игрока» в игреЭто позволяет редактировать в режиме карьеры бутсы/носки/браслетыДля последующего редактирования игроков через таблицу активировать это меню обязательно. Для изменения игрока нам требуется зайти в режим редактирования выбранного игрока в самой игре. Далее в дело вступает наша таблица. Easy Player Edit
Name — По идее изменяет Имя игрока, но использовать не советую. Position ID — Изменяет основную позицию игрокаJersey number — Номер на футболкеNationality — НациональностьBirth Year/Month/Day — Дата рождения игрока
Playing Style/Save style — Стиль игры/сейвов игрока
Height — РостWeight — ВесBody Type — ТелосложениеPreferred Foot — Рабочая нога
Непосредственно изменение скиллов игрока
Стили исполнения штрафных/пенальти. Стиль бега/Празднование
Player DataИЗМЕНЕНИЕ ЭТИХ ДАННЫХ МОЖЕТ ПОВЛЕЧЬ ЗА СОБОЙ ВЫЛЕТЫ ИЗ ИГРЫПоэтому советую делать дубликаты сохранений. Player InfoНа картинке ниже обозначены те строки которые можно смело изменять
По сути тоже самое что и в меню «Easy Player Edit»
Это таланты игрока. Выбираете нужный и меняете 0 на 1.
Изменение бутс игрока.
Это очень интересное меню, здесь можно поменять внешность и прическу игроку. Непосредственно «headtypecode» отвечает за лицо, «hairtypecode» за прическу, а «haircolorcode» за цвет волос. Вот пример что можно натворить:
На скриншоте представлено действие замены лица и прически, для примера взяты данные от Раджа Наингголан.
Тоже крайне полезное меню, тут нам предоставляется возможность изменить:
- Звезды особых приёмов
- Звезды слабой ноги
- Воркрейты в Атаке/Защите
- Стиль бега
С редактором игроков закончили, переходим дальшеPlayer TrainingЭто пеню отвечает за тренировки игроков в режиме карьеры.
- Remove countdown – убирает 5 секундное ожидание при симулировании тренировки.
- More efficient training – Сильно увеличивает эффект от тренировок
- Unlimited Training Sessions – позволяет бесконечно тренироваться за 1 день.
- Training Everyday – Тренировки каждый день
- Trainingsim – A – Все тренировки проходят на оценку А
Бывший сотрудник PlayGround
В разработке корпоративных приложений очень часто приходится решать задачу выгрузки данных в документы — от небольших справок до больших отчетов.
Хочу поделиться нашим opensource-решением для генерации docx документов, которое позволяет заполнять документы по шаблону, оформление которого можно менять в Word без переписывания кода.
Для начала — немного вводных.
Что нам было нужно от шаблонизатора
- Шаблон создается в Word и сразу видно, на что будет похож результирующий документ, шаблон без лишнего мусора.
- Результирующий документ после скачивания содержит все необходимые данные, не подтягивая их с внешних источников.
- Возможность заполнять списки, таблицы, и иногда еще и таблицы с вложенными в них списками.
- Шаблон можно доверить секретарю клиента, чтобы он мог сменить логотип, реквизиты компании, или как-либо еще подкорректировать оформление. И все это уже после сдачи проекта, не модифицируя наш код.
Поиски шаблонизатора
Со стороны кода мы работаем с привычными сущностями, такими как «Таблица», «Список», «Строка», «Ячейка».
Например, необходимо заполнить таблицу, указать дату её заполнения и количество записей. Создадим шаблон этой таблицы в Word-документе:
Каждое поле, которое мы будем заполнять, необходимо поместить в контрол, связать его с данными в коде. Для этого:
- Выделяем текст, который будет заполняемым полем.
- Нажимаем «Вставить элемент управления содержимым «Форматированный текст».
- Нажимаем «Свойства» и заполняем поля «Название» и «Тег».
Если требуется заполнить таблицу или список, их также нужно поместить в отдельный контент-контрол.
Так выглядит шаблон с добавленными элементами управления содержимым:
Теперь заполним шаблон данными:
нам нужно добавить одно поле и одну таблицу с двумя строчками, и в футере таблицы указать количество записей.
var valuesToFill = new Content(
new FieldContent(«Report date», DateTime. Now. Date. ToString()),
new TableContent(«Team members»). AddRow(
new FieldContent(«Full name», «Семёнов Илья Васильевич»),
new FieldContent(«Role», «Разработчик»)). AddRow(
new FieldContent(«Full name», «Петров Фёдор Анатольевич»),
new FieldContent(«Role», «Разработчик»)). AddRow(
new FieldContent(«Full name», «Артемьев Вячеслав Геннадьевич»),
new FieldContent(«Role», «Ведущий разработчик»)),
new FieldContent(«Count», «3»)
);
Если всё получилось, на выходе следующий документ:
С помощью метода SetRemoveContentControls(bool value) можно удалить элементы управления содержимым, если они уже не нужны в результирующем документе.
Еще больше примеров!
Заполнение простых полей
var valuesToFill = new Content(new FieldContent(«Report date», DateTime. Now. ToString()));
var valuesToFill = new Content(
new TableContent(«Team Members Table»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»)). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»)),
new FieldContent(«Count», «2»));
var valuesToFill = new Content(
new ListContent(«Team Members List»). AddItem(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»)). AddItem(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»)));
Заполнение вложенных списков
var valuesToFill = new Content(
new ListContent(«Team Members Nested List»). AddItem(new ListItemContent(«Role», «Program Manager»). AddNestedItem(new FieldContent(«Name», «Eric»)). AddNestedItem(new FieldContent(«Name», «Ann»))). AddItem(new ListItemContent(«Role», «Developer»). AddNestedItem(new FieldContent(«Name», «Bob»)). AddNestedItem(new FieldContent(«Name», «Richard»))));
Таблица внутри списка
var valuesToFill = new Content(
new ListContent(«Projects List»). AddItem(new ListItemContent(«Project», «Project one»). AddTable(TableContent. Create(«Team members»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»)). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»)))). AddItem(new ListItemContent(«Project», «Project two»). AddTable(TableContent. Create(«Team members»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»)))). AddItem(new ListItemContent(«Project», «Project three»). AddTable(TableContent. Create(«Team members»). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»)))));
Список внутри таблицы
var valuesToFill = new Content(
new TableContent(«Projects Table»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»),
new ListContent(«Projects»). AddItem(new FieldContent(«Project», «Project one»)). AddItem(new FieldContent(«Project», «Project two»))). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»),
new ListContent(«Projects»). AddItem(new FieldContent(«Project», «Project one»)). AddItem(new FieldContent(«Project», «Project three»))));
Таблица, состоящая из нескольких блоков, которые заполняются независимо
var valuesToFill = new Content(
new TableContent(«Team Members Statistics»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»)). AddRow(
new FieldContent(«Name», «Richard»),
new FieldContent(«Role», «Program Manager»)). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»)),
new TableContent(«Team Members Statistics»). AddRow(
new FieldContent(«Statistics Role», «Program Manager»),
new FieldContent(«Statistics Role Count», «2»)). AddRow(
new FieldContent(«Statistics Role», «Developer»),
new FieldContent(«Statistics Role Count», «1»)));
Таблица с объединенными вертикально ячейками
var valuesToFill = new Content(
new TableContent(«Team members info»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»),
new FieldContent(«Age», «37»),
new FieldContent(«Gender», «Male»)). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»),
new FieldContent(«Age», «33»),
new FieldContent(«Gender», «Male»)). AddRow(
new FieldContent(«Name», «Ann»),
new FieldContent(«Role», «Developer»),
new FieldContent(«Age», «34»),
new FieldContent(«Gender», «Female»)));
Таблица с объединенными горизонтально ячейками
var valuesToFill = new Content(
new TableContent(«Team members projects»). AddRow(
new FieldContent(«Name», «Eric»),
new FieldContent(«Role», «Program Manager»),
new FieldContent(«Age», «37»),
new FieldContent(«Projects», «Project one, Project two»)). AddRow(
new FieldContent(«Name», «Bob»),
new FieldContent(«Role», «Developer»),
new FieldContent(«Age», «33»),
new FieldContent(«Projects», «Project one»)). AddRow(
new FieldContent(«Name», «Ann»),
new FieldContent(«Role», «Developer»),
new FieldContent(«Age», «34»),
new FieldContent(«Projects», «Project two»)));
Где скачать
Всем спасибо за внимание, надеемся, что данный инструмент поможет вам в ваших проектах.
Создаем подключения и таблицы
Создаем подключения к БД
* код функций read_data и clear_db есть в репозитории.
Создаем таблицы классическим путем через SQL
* код функции read_query есть в репозитории. Тексты запросов также есть в репозитории.
По сути мы создаем пакетами справочники (жанры, музыкантов, альбомы, коллекции), а затем в цикле связываем остальные данные и строим вручную промежуточные таблицы. Запускаем код и видим что БД создалась. Главное не забыть вызывать commit() у сессии.
Теперь пробуем сделать тоже самое, но с применением ORM подхода. Для того чтобы работать с ORM нам надо описать классы данных. Для этого мы создадим 8 классов (по одному на кажую таблицу).
Список классов БД
Код скрипта объявления классов.
Base = declarative_base()
class Genre(Base):
__tablename__ = ‘genres’
id = sa. Column(sa. Integer, primary_key=True, autoincrement=True)
name = sa. Column(sa. String(20), unique=True)
# Объявляется отношение многие ко многим к Musician через промежуточную таблицу genres_musicians
musicians = relationship(«Musician», secondary=’genres_musicians’)
class Musician(Base):
__tablename__ = ‘musicians’
id = sa. Column(sa. Integer, primary_key=True, autoincrement=True)
name = sa. Column(sa. String(50), unique=True)
# Объявляется отношение многие ко многим к Genre через промежуточную таблицу genres_musicians
genres = relationship(«Genre», secondary=’genres_musicians’)
# Объявляется отношение многие ко многим к Album через промежуточную таблицу albums_musicians
albums = relationship(«Album», secondary=’albums_musicians’)
class GenreMusician(Base):
__tablename__ = ‘genres_musicians’
# здесь мы объявляем составной ключ, состоящий из двух полей
__table_args__ = (PrimaryKeyConstraint(‘genre_id’, ‘musician_id’),)
# В промежуточной таблице явно указываются что следующие поля являются внешними ключами
genre_id = sa. Column(sa. Integer, sa. ForeignKey(‘genres. id’))
musician_id = sa. Column(sa. Integer, sa. ForeignKey(‘musicians. id’))
class Album(Base):
__tablename__ = ‘albums’
id = sa. Column(sa. Integer, primary_key=True, autoincrement=True)
name = sa. Column(sa. String(50), unique=True)
year = sa. Column(sa. Integer)
# Объявляется отношение многие ко многим к Musician через промежуточную таблицу albums_musicians
musicians = relationship(«Musician», secondary=’albums_musicians’)
class AlbumMusician(Base):
__tablename__ = ‘albums_musicians’
# здесь мы объявляем составной ключ, состоящий из двух полей
__table_args__ = (PrimaryKeyConstraint(‘album_id’, ‘musician_id’),)
# В промежуточной таблице явно указываются что следующие поля являются внешними ключами
album_id = sa. Column(sa. Integer, sa. ForeignKey(‘albums. id’))
musician_id = sa. Column(sa. Integer, sa. ForeignKey(‘musicians. id’))
class Track(Base):
__tablename__ = ‘tracks’
id = sa. Column(sa. Integer, primary_key=True, autoincrement=True)
name = sa. Column(sa. String(100))
length = sa. Column(sa. Integer)
# Поскольку по полю album_id идет связь один ко многим, достаточно указать чей это внешний ключ
album_id = sa. Column(sa. Integer, ForeignKey(‘albums. id’))
# Объявляется отношение многие ко многим к Collection через промежуточную таблицу collections_tracks
collections = relationship(«Collection», secondary=’collections_tracks’)
class Collection(Base):
__tablename__ = ‘collections’
id = sa. Column(sa. Integer, primary_key=True, autoincrement=True)
name = sa. Column(sa. String(50))
year = sa. Column(sa. Integer)
# Объявляется отношение многие ко многим к Track через промежуточную таблицу collections_tracks
tracks = relationship(«Track», secondary=’collections_tracks’)
class CollectionTrack(Base):
__tablename__ = ‘collections_tracks’
# здесь мы объявляем составной ключ, состоящий из двух полей
__table_args__ = (PrimaryKeyConstraint(‘collection_id’, ‘track_id’),)
# В промежуточной таблице явно указываются что следующие поля являются внешними ключами
collection_id = sa. Column(sa. Integer, sa. ForeignKey(‘collections. id’))
track_id = sa. Column(sa. Integer, sa. ForeignKey(‘tracks. id’))
Нам достаточно создать базовый класс Base для декларативного стиля описания таблиц и унаследоваться от него. Вся магия отношений между таблицами заключается в правильном использовании relationship и ForeignKey. В коде указано в каком случае мы создаем какое отношение. Главное не забыть прописать relationship с обеих сторон связи «многие ко многим».
Непосредственно создание таблиц с использованием ORM подхода происходит путем вызова:
Base. metadata. create_all(engine_orm)
И вот тут включается магия, буквально все классы, объявленные в коде через наследование от Base становятся таблицами. Сходу я не увидел как указать экземпляры каких классов надо создать сейчас, а какие отложить для создания позже (например в другой БД). Наверняка такой способ есть, но в нашем коде все классы-наследники Base инстанцируются одномоментно, имейте это ввиду.
Обновление от 08. 20: создать отдельные таблицы можно используя следующий синтаксис:
Но для этого требуется инстанцировать объекты классов.
Наполнение таблиц при использовании ORM подхода выглядит так:
Заполнение таблиц данными через ORM
Приходится поштучно заполнять каждый справочник (жанры, музыканты, альбомы, коллекции). В случае SQL запросов можно было генерировать пакетное добавление данных. Зато промежуточные таблицы в явном виде не надо создавать, за это отвечают внутренние механизмы SQLAlchemy.
Запросы к базам
По заданию нам надо написать 15 запросов используя обе техники SQL и ORM. Вот список поставленных вопросов в порядке возрастания сложности:
- название и год выхода альбомов, вышедших в 2018 году;
- название и продолжительность самого длительного трека;
- название треков, продолжительность которых не менее 3,5 минуты;
- названия сборников, вышедших в период с 2018 по 2020 год включительно;
- исполнители, чье имя состоит из 1 слова;
- название треков, которые содержат слово «me».
- количество исполнителей в каждом жанре;
- количество треков, вошедших в альбомы 2019-2020 годов;
- средняя продолжительность треков по каждому альбому;
- все исполнители, которые не выпустили альбомы в 2020 году;
- названия сборников, в которых присутствует конкретный исполнитель;
- название альбомов, в которых присутствуют исполнители более 1 жанра;
- наименование треков, которые не входят в сборники;
- исполнителя(-ей), написавшего самый короткий по продолжительности трек (теоретически таких треков может быть несколько);
- название альбомов, содержащих наименьшее количество треков.
Как видите, вышеизложенные вопросы подразумевают как простую выборку так и с объединением таблиц, а также использование агрегатных функций.
Ниже предоставлены решения по каждому из 15 запросов в двух вариантах (используя SQL и ORM). В коде запросы идут парами, чтобы показать идентичность результатов на выводе в консоль.
Запросы и их краткое описание
Для тех, кому не хочется погружаться в чтение кода, я попробую показать как выглядит «сырой» SQL и его альтернатива в ORM выражении, поехали!
Шпаргалка по сопоставлению SQL запросов и ORM выражений
название и год выхода альбомов, вышедших в 2018 году:
SQL
session_orm. query(Album). filter_by(year=2018)
название и продолжительность самого длительного трека:
SQL
session_orm. query(Track). order_by(Track. length. desc()). slice(0, 1)
название треков, продолжительность которых не менее 3,5 минуты:
SQL
session_orm. query(Track). filter(310 <= Track. length). order_by(Track. length. desc())
названия сборников, вышедших в период с 2018 по 2020 год включительно:
SQL
session_orm. query(Collection). filter(2018 <= Collection. year, Collection. year <= 2020)
* обратите внимание что здесь и далее фильтрация задается уже с использованием filter, а не с использованием filter_by.
исполнители, чье имя состоит из 1 слова:
SQL
select name
from musicians
where not name like ‘%% %%’
session_orm. query(Musician). filter(Musician. name. notlike(‘%% %%’))
название треков, которые содержат слово «me»:
SQL
select name
from tracks
where name like ‘%%me%%’
session_orm. query(Track). filter(Track. name. like(‘%%me%%’))
количество исполнителей в каждом жанре:
SQL
select g. name, count(m. name)
from genres as g
left join genres_musicians as gm on g. id = gm. genre_id
left join musicians as m on gm. musician_id = m. id
group by g. name
order by count(m. id) DESC
session_orm. query(Genre). join(Genre. musicians). order_by(func. count(Musician. id). desc()). group_by(Genre. id)
количество треков, вошедших в альбомы 2019-2020 годов:
SQL
session_orm. query(Track, Album). join(Album). filter(2019 <= Album. year, Album. year <= 2020)
средняя продолжительность треков по каждому альбому:
SQL
select a. name, AVG(t. length)
from albums as a
left join tracks as t on t. album_id = a. id
group by a. name
order by AVG(t. length)
session_orm. query(Album, func. avg(Track. length)). join(Track). order_by(func. avg(Track. length)). group_by(Album. id)
все исполнители, которые не выпустили альбомы в 2020 году:
SQL
select distinct m. name
from musicians as m
where m. name not in (
select distinct m. name
from musicians as m
left join albums_musicians as am on m. id = am. musician_id
left join albums as a on a. id = am. album_id
where a. year = 2020
)
order by m. name
subquery = session_orm. query(distinct(Musician. name)). join(Musician. albums). filter(Album. year == 2020)
session_orm. query(distinct(Musician. name)). filter(~Musician. name. in_(subquery)). order_by(Musician. name. asc())
названия сборников, в которых присутствует конкретный исполнитель (Steve):
SQL
select distinct c. name
from collections as c
left join collections_tracks as ct on c. id = ct. collection_id
left join tracks as t on t. id = ct. track_id
left join albums as a on a. id = t. album_id
left join albums_musicians as am on am. album_id = a. id
left join musicians as m on m. id = am. musician_id
where m. name like ‘%%Steve%%’
order by c. name
session_orm. query(Collection). join(Collection. tracks). join(Album). join(Album. musicians). filter(Musician. name == ‘Steve’). order_by(Collection. name)
название альбомов, в которых присутствуют исполнители более 1 жанра:
SQL
наименование треков, которые не входят в сборники:
SQL
select t. name
from tracks as t
left join collections_tracks as ct on t. id = ct. track_id
where ct. track_id is null
session_orm. query(Track). outerjoin(Track. collections). filter(Collection. id == None)
* обратите внимание что несмотря на предупреждение в PyCharm надо именно так составлять условие фильтрации, если написать как предлагает IDE («Collection. id is None») то оно работать не будет.
исполнителя(-ей), написавшего самый короткий по продолжительности трек (теоретически таких треков может быть несколько):
SQL
select m. name, t. length
from tracks as t
left join albums as a on a. id = t. album_id
left join albums_musicians as am on am. album_id = a. id
left join musicians as m on m. id = am. musician_id
group by m. name, t. length
having t. length = (select min(length) from tracks)
order by m. name
subquery = session_orm. query(func. min(Track. length))
session_orm. query(Musician, Track. length). join(Musician. albums). join(Track). group_by(Musician. id, Track. length). having(Track. length == subquery). order_by(Musician. name)
название альбомов, содержащих наименьшее количество треков:
SQL
select distinct a. name
from albums as a
left join tracks as t on t. album_id = a. id
where t. album_id in (
select album_id
from tracks
group by album_id
having count(id) = (
select count(id)
from tracks
group by album_id
order by count
limit 1
)
)
order by a. name
subquery1 = session_orm. query(func. count(Track. id)). group_by(Track. album_id). order_by(func. count(Track. id)). limit(1)
subquery2 = session_orm. query(Track. album_id). group_by(Track. album_id). having(func. count(Track. id) == subquery1)
session_orm. query(Album). join(Track). filter(Track. album_id. in_(subquery2)). order_by(Album. name)
Как видите, вышеизложенные вопросы подразумевают как простую выборку так и с объединением таблиц, а также использование агрегатных функций и подзапросов. Все это реально сделать с SQLAlchemy как в режиме SQL так и в режиме ORM. Разноообразие операторов и методов позволяет выполнить запрос наверное любой сложности.
Надеюсь данный материал поможет начинающим быстро и эффективно начать составлять запросы.
Архитектура
Hive представляет из себя движок, который превращает SQL-запросы в цепочки map-reduce задач. Движок включает в себя такие компоненты, как Parser(разбирает входящие SQL-запрсоы), Optimimer(оптимизирует запрос для достижения большей эффективности), Planner (планирует задачи на выполнение) Executor(запускает задачи на фреймворке MapReduce.
Для работы hive также необходимо хранилище метаданных. Дело в том что SQL предполагает работу с такими объектами как база данных, таблица, колонки, строчки, ячейки и тд. Поскольку сами данные, которые использует hive хранятся просто в виде файлов на hdfs — необходимо где-то хранить соответствие между объектами hive и реальными файлами.
В качестве metastorage используется обычная реляционная СУБД, такая как MySQL, PostgreSQL или Oracle.
Command line interface
Для того чтобы попробовать работу с hive проще всего воспользоваться его командной строкой. Современная утилита для работы с hive называется beeline (привет нашим партнёрам из одноименного оператора 🙂 ) Для этого на любой машине в hadoop-кластере (см. наш туториал по hadoop) с установленным hive достаточно набрать команду.
Далее необходимо установить соединение с hive-сервером:
root root — в данном контексте это имя пользователя и пароль. После этого вы получите командную строку, в которой можно вводить команды hive.
Также иногда бывает удобно не вводить sql-запросы в командную строку beeline, а предварительно сохранить и редактировать их в файле, а потом выполнить все запросы из файла. Для этого нужно выполнить beeline с параметрами подключения к базе данных и параметром -f указывающим имя файла, содержащего запросы:
beeline -u jdbc:hive2://localhost:10000/default -n root -p root -f sorted. sql
Data Units
При работе с hive можно выделить следующие объекты которыми оперирует hive:
- База данных
- Таблица
- Партиция (partition)
- Бакет (bucket)
Разберем каждый из них подробнее:
База данных
База данных представляет аналог базы данных в реляционных СУБД. База данных представляет собой пространство имён, содержащее таблицы. Команда создания новой базы данных выглядит следующим образом:
Database и Schema в данном контексте это одно и тоже. Необязательная добавка IF NOT EXISTS как не сложно догадаться создает базу данных только в том случае если она еще не существует.
Пример создания базы данных:
Для переключения на соответствующую базу данных используем команду USE:
Таблица
Таблица в hive представляет из себя аналог таблицы в классической реляционной БД. Основное отличие — что данные hive’овских таблиц хранятся просто в виде обычных файлов на hdfs. Это могут быть обычные текстовые csv-файлы, бинарные sequence-файлы, более сложные колоночные parquet-файлы и другие форматы. Но в любом случае данные, над которыми настроена hive-таблица очень легко прочитать и не из hive.
Таблицы в hive бывают двух видов:
Классическая таблица, данные в которую добавляются при помощи hive. Вот пример создания такой таблицы (источник примера):
CREATE TABLE IF NOT EXISTS employee ( eid int, name String,
salary String, destination String)
COMMENT ‘Employee details’
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ‘ ‘
LINES TERMINATED BY ‘
‘
STORED AS TEXTFILE;
Тут мы создали таблицу, данные в которой будут храниться в виде обычных csv-файлов, колонки которой разделены символом табуляции. После этого данные в таблицу можно загрузить. Пусть у нашего пользователя в домашней папке на hdfs есть (напоминаю, что загрузить файл можно при помощи hadoop fs -put) файл sample. txt вида:
Загрузить данные мы сможем при помощи следующей команды:
После hive переместит данныe, хранящемся в нашем файле в хранилище hive. Убедиться в этом можно прочитав данные напрямую из файла в хранилище hive в hdfs:
Классические таблицы можно также создавать как результат select-запроса к другим таблицам:
Кстати говоря, SELECT для создания таблицы в данном случае уже запустит mapreduce-задачу.
Внешняя таблица, данные в которую загружаются внешними системами, без участия hive. Для работы с внешними таблицами при создании таблицы нужно указать ключевое слово EXTERNAL, а также указать путь до папки, по которому хранятся файлы:
После этого таблицей можно пользоваться точно так же как и обычными таблицами hive. Самое удобное в этом, что вы можете просто скопировать файл в нужную папочку в hdfs, а hive будет автоматом подхватывать новые файлы при запросах к соответствующей таблице. Это очень удобно при работе например с логами.
Партиция (partition)
Так как hive представляет из себя движок для трансляции SQL-запросов в mapreduce-задачи, то обычно даже простейшие запросы к таблице приводят к полному сканированию данных в этой таблицы. Для того чтобы избежать полного сканирования данных по некоторым из колонок таблицы можно произвести партиционирование этой таблицы. Это означает, что данные относящиеся к разным значениям будут физически храниться в разных папках на HDFS.
Для создания партиционированной таблицы необходимо указать по каким колонкам будет произведено партиционирование:
CREATE TABLE IF NOT EXISTS employee_partitioned ( eid int, name String,
salary String, destination String)
COMMENT ‘Employee details’
PARTITIONED BY (birth_year int, birth_month string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ‘ ‘
LINES TERMINATED BY ‘
‘
STORED AS TEXTFILE;
При заливке данных в такую таблицу необходимо явно указать, в какую партицию мы заливаем данные:
Посмотрим теперь как выглядит структура директорий:
Видно, что структура директорий выглядит таким образом, что каждой партиции соответствует отдельная папка на hdfs. Теперь, если мы будем запускать какие-либо запросы, у казав в условии WHERE ограничение на значения партиций — mapreduce возьмет входные данные только из соответствующих папок.
В случае External таблиц партиционирование работает аналогичным образом, но подобную структуру директорий придется создавать вручную.
Партиционирование очень удобно например для разделения логов по датам, так как правило любые запросы за статистикой содержат ограничение по датам. Это позволяет существенно сократить время запроса.
Бакет
Партиционирование помогает сократить время обработки, если обычно при запросах известны ограничения на значения какого-либо столбца. Однако оно не всегда применимо. Например — если количество значений в столбце очень велико. Напрмер — это может быть ID пользователя в системе, содержащей несколько миллионов пользователей.
В этом случае на помощь нам придет разделение таблицы на бакеты. В один бакет попадают строчки таблицы, для которых значение совпадает значение хэш-функции вычисленное по определенной колонке.
При любой работе с бакетированными таблицами необходимо не забывать включать поддержку бакетов в hive (иначе hive будет работать с ними как с обычными таблицами):
set hive. enforce. bucketing=true;
Для создания таблицы разбитой на бакеты используется конструкция CLUSTERED BY
set hive. enforce. bucketing=true;
CREATE TABLE employee_bucketed ( eid int, name String, salary String, destination String)
CLUSTERED BY(eid) INTO 10 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ‘ ‘
LINES TERMINATED BY ‘
‘
STORED AS TEXTFILE;
Так как команда Load используется для простого перемещения данных в хранилище hive — в данном случае для загрузки она не подходит, так как данные необходимо предобработать, правильно разбив их на бакеты. Поэтому их нужно загрузить при помощи команды INSERT из другой таблицы(например из внешней таблицы):
set hive. enforce. bucketing=true;
FROM employee_external INSERT OVERWRITE TABLE employee_bucketed SELECT *;
После выполнения команды убедимся, что данные действительно разбились на 10 частей:
Теперь при запросах за данными, относящимися к определенному пользователю, нам не нужно будет сканировать всю таблицу, а только 1/10 часть этой таблицы.
Checklist по использованию hive
Теперь мы разобрали все объекты, которыми оперирует hive. После того как таблицы созданы — можно работать с ними, так как с таблицами обычных баз данных. Однако не стоит забывать о том что hive — это все же движок по запуску mapreduce задач над обычными файлами, и полноценной заменой классическим СУБД он не является. Необдуманное использование таких тяжелых команд, как JOIN может привести к очень долгим задачам. Поэтому прежде чем строить вашу архитектуру на основе hive — необходимо несколько раз подумать. Приведем небольшой checklist по использованию hive:
- Данных которые надо обрабатывать много и они не влазят на диск одной машины (иначе лучше подумать над классическими SQL-системами).
- Данные в основном только добавляются и редко обновляются (если обновления часты — возможно стоит подумать об использовании Hbase например, см наш предыдущий материал.
- Данные имеют хорошо структурированную структуру и хорошо разбиваются на колонки.
- Паттерны обработки данных хорошо описываются декларативным языком запросов (SQL).
- Время ответа на запрос не критично(так как hive работает на основе MapReduce — интерактивности ждать не стоит).
Заключение
В данной статье мы разобрали архитектуру hive, data unit-ы, которыми оперирует hive, привели примеры по созданию и заполнению таблиц hive. В следующей статье цикла мы рассмотрим продвинутые возможности hive, включающие в себя:
- Транзакционную модель
- Индексы
- Интеграцию hive с хранилищами данных, отличными от hdfs
Youtube-Канал автора об анализе данных
Ссылки на предыдущие статьи цикла:
» Big Data от А до Я. Часть 1: Принципы работы с большими данными, парадигма MapReduce
» Big Data от А до Я. Часть 2: Hadoop
» Big Data от А до Я. Часть 3: Приемы и стратегии разработки MapReduce-приложений
» Big Data от А до Я. Часть 4: Hbase