When the whole world is your database
Что делать, когда база данных — весь мир?

RubyMeditation #14, апрель 2017

Виктор Шепелев (zverok)

Представьте, что все данные мира уже доступны

…из Ruby

Например, так:

1Ukraine.president.tweets.last
2# => "Рішення Європарламенту – це яскравий маркер, що Україна –
3#     частина об’єднаної Європи, від Лісабона до Харкова"
4
5Lisbon.distance_to(Kharkiv)
6# => 3,757 km

Или так:

1Africa.countries.sort_by(&:population).reverse.first(3)
2# => [#<Nigeria>, #<Ethiopia>, #<Egypt>]

…или так:

1Kharkiv.road_to(Kyiv).cities.map(&:current_weather)
2# => [#<+19°C, sunny>, #<+15°C, rain>, #<18°C, clouds>, ....

или так:

1Ukraine.president.at(2012).quotations(:uk).grep(/заздрить/)
2# => "Якщо мені хтось заздрить, я скажу — правильно робить, нехай спробують так жити."

Есть ли где взять эти данные?

Ага!

1Ukraine.president.tweets.last
2#   ^         ^         ^
3# wiki   wikidata    twitter
1Lisbon.distance_to(Kharkiv)
2# ^      ^           ^
3# wiki  math       wiki
1Kharkiv.road_to(Kyiv).cities.map(&:current_weather)
2#  ^                 ^              ^
3# wiki      openstreetmap      openweathermap

…и так далее.

А какая польза?

Когда общие знания под рукой, это помогает пользователю приложения сделать осмысленный выбор.

То есть, то что люди могут легко найти…

…но ленятся.

А программы могли бы показывать — но не умеют.

  • Продажа авиабилетов: какая там погода, валюта, криминальная обстановка, бары? Что с визой?
  • Сайт с кинорецензиями: что ещё снял этот режиссёр? Что ещё снимали в этом городе? Сколько лет актёрам (в сравнении с героями)? Сравнить бюджет фильма с классическими фильмами.
  • Новость про безвиз: данные для инфографики «кому ещё дали, какая у них экономика, сколько от них лететь, что у них с политикой»?

Всё по отдельности — несложно. Объединять сложнее.

И ещё…

Учёба: стандартное «напиши калькулятор» против «сравни длительность марсианских миссий»

Эксперименты: заполнить таблицы, дать реалистичные данные для графиков, быстро проверить теорию.

Наука: мы опоздали на праздник, но когда-то Rails казались опоздавшими на праздник веб-разработки…

А кроме того…

Просто интересная задача!

Решая её, можно найти подходы к:

  • интеграции данных из разнородных API;
  • развитию базовых библиотек языка;
  • уточнению подходов к типизации сложных данных.

ОК, а в чём проблема?

HERE BE DRAGONS

  • сложность протоколов запросов (пример: запрос к Википедии)
    https://en.wikipedia.org/w/api.php?action=query&titles=Argentina&prop=revisions&rvprop=content&format=json
    
  • негомогенность ответов (пример: извлечение текста из страницы Википедии)
    1response['query']['revisions'].first['*']
    
  • отсутствие общего знаменателя (пример: а теперь — язык запросов к OpenStreetMap)
    node["name"~"holtorf"](50.7,7.1,50.8,7.25);
    out body;
    

И что делать?..

Богатая система значений

1Kharkiv.temperature # => #<Measure 11°C>
2Kharkiv.temperature > Kyiv.temperature
3# => true
4
5Kharkiv.population # => # => #<Measure 1,439,733 person>
6Kyiv.population / Kharkiv.population
7# => 2.02
1Kharkiv.coord # => #<Geo::Coord(50°0′0″N,36°13′45″E)>
2Kharkiv.coord.distance_to(Kyiv.coord) # => #<Measure 409 km>
1Kharkiv.tz_offset # => #<TZOffset UTC+02:00>
2Kharkiv.tz_offset.now # => 2017-04-08 00:12:50 +0200

*Тут бы ещё поговорить о dry-struct и других похожих гемах

Плоская система типов

  • Мы возвращаемся к обычным «словарям» (почти как в JavaScript!) ;
  • Но даже вложенные словари нам не нужны:
    • каждый ключ нашей «сущности» (Entity) это либо «значение»,
    • …либо ссылка на другую Entity.

Плоская система типов: пример

 1Kharkiv.describe
 2# => #<Entity:Kharkiv>
 3#               area: #<Measure 350 km²>                  | < базовые значения
 4#              coord: #<Geo::Coord 50°0′0″N,36°13′45″E>   |
 5#            country: #<Reality::Entity?(Ukraine)>        | < ссылка на связанный объект
 6# head_of_government: #<Reality::Entity?(Hennadiy Kernes)>| < ссылка на какого-то урода
 7#         created_at: #<Date: 1654-01-01>                 | ...и т.д.
 8#          elevation: #<Measure 152 m>
 9#   official_website: "http://www.city.kharkov.ua/"
10#         population: #<Measure 1,439,733 person>
11#          tz_offset: #<TZOffset UTC+02:00>

Квалификация полей

По времени

1Kharkiv.temperature(at: '2016-01-03')
2# => #<Measure -1°C>
3Kharkiv.temperature(at: Date.today + 10.days)
4# => #<Measure +20°C>
5Kharkiv.temperature
6# => ...available from 2016 to today + 10 days, currently +12°C

По источнику

1Kharkiv.temperature(from: :forecast_io) # => #<Measure +12°C>
2Kharkiv.temperature(from: :open_weather_map) # => #<Measure +15°C>

Выборки, фильтры и индексы

Выборки, фильтры и индексы: Википедия/Викидата

Выборки, фильтры и индексы: другие источники

Что у нас есть

$ gem install reality
1 gem installed
$ reality --interactive
1> Reality.search(wikipedia: 'The Matrix').quotations(author: 'Morpheus').grep(/Welcome/)
2# => "Welcome... to the desert of the real."

*на самом деле нет

**но уже почти!

Что у нас есть (на самом деле)

 1m = Entity('The Matrix')
 2# => #<Reality::Entity(The Matrix)>
 3m.describe
 4# ------------------------------
 5# #<Reality::Entity(The Matrix)>
 6# ------------------------------
 7#              actors: #<Reality::List[Hugo Weaving?, Keanu Reeves?, Laurence Fishburne?, Carrie-Anne Moss?, Joe Pantoliano?, Gloria Foster?, Robert Taylor?, Marcus Chong?, Paul Goddard?, Matt Doran?, Ada Nicodemou?, Steve Dodd?, Anthony Ray Parker?, Paul Goddard?, Belinda McClory?, Julian Arahanga?, Jeremy Ball?, Rowan Witt?]>
 8#           directors: #<Reality::List[The Wachowskis?, Lilly Wachowski?, Lana Wachowski?]>
 9#              genres: ["cyberpunk", "action film", "science fiction film", "post-apocalyptic film", "thriller film", "action thriller", "dystopian film", "science fiction action film"]
10#         nominations: #<Reality::List[Academy Award for Best Film Editing?, Academy Award for Best Visual Effects?, Academy Award for Best Sound Editing?, Academy Award for Best Sound Mixing?]>
11#        published_at: #<Date: 1999-03-31>
1m.actors.first(3).each{|a| puts "#{a.name}: #{a.age_at(m.published_at)}"}
2# Hugo Weaving: 38
3# Keanu Reeves: 34
4# Laurence Fishburne: 37

*а вот это правда работает

И это тоже:

1Entity('Kharkiv').coord.distance_to(Entity('Kyiv').coord)
2# => #<Reality::Measure(409 km)>

И это:

1Entity('Ruby (programming language)').developers.first.birth_place
2# => #<Reality::Entity?(Ōsaka Prefecture)>

Что мы делаем (reality/develop)

Цель: сохранить прикольность, добавить практичности.

$ git clone git@github.com:molybdenum-99/reality.git
$ cd reality
$ git checkout develop

Что мы делаем (reality/develop)

Observation — наблюдение: именованные и квалифицированные значения:

 1o = Observation.new(:temperature, Measure['°C'].new(10))
 2#<Observation temperature=10°C>
 3o = Observation.new(:temperature, Measure['°C'].new(10), at: '2017-04-08 22:30')
 4#<Observation temperature=10°C at 2017-04-08 22:30>
 5o = Observation.new(:temperature, Measure['°C'].new(10), at: '2017-04-08 22:30', source: yahooweather)
 6#<Observation temperature=10°C at 2017-04-08 22:30 (yahooweather)>
 7
 8os = Observations.new(....list of observations....)
 9os.at(timestamp) # => like "president of USA in 2012"
10os.from(:worldbank) # => like "population of Guatemala according to Worldbank"

Что мы делаем (reality/develop)

Entity — список “наблюдений”, связанных с одним объектом, из одного или многих источников:

 1kh = Reality.get(wikipedia: 'Kharkiv')
 2# => #<Entity wikipedia:Kharkiv, wikidata:Q42308?>
 3kh.describe
 4#    country: #<Link Ukraine>
 5# population: #<Measure 1,439,733 person>
 6# ....
 7#
 8# other sources: wikidata, openweathermap
 9
10kh2 = kh.load(:wikidata)
11# => #<Entity wikipedia:Kharkiv, wikidata:Q42308, openstreetmap:3154746?>

Что мы делаем (reality/develop)

DataSource: источник данных. Нечто, умеющее делать так:

1Reality.wikipedia.get('Einstein') # => list of observations
2Reality.wikipedia.search(/Guardians/) # => list of lists

…и становящееся источником entities!

Что мы делаем (reality/develop)

Источники, которые работают или близки к тому:

(Не такое далёкое) Будущее

Ближайшие планы:

  • Собрать всё вместе и сделать новый большой релиз;
  • Добавить OpenStreetMap, Wikivoyage, Wikiquote и множество способов поиска данных;
  • …и пойти дальше.

Join the reality!

Ссылки:

Я:

  • Віктор Шепелєв, 34 роки, Харків, Україна;
  • 15+ лет разработки, 10+ — на Руби; Toptal, mkdev.me, SciRuby;
  • zverok.github.io, zverok.offline@gmail.com, zver_ok@Skype, gitter.im/zverok;

Благодарности:

  • Сергій Мостовий, двигатель разработки первой версии;
  • The Ruby Association, которая дала на неё грант;
  • RubyMeditation за приглашение прочитать это доклад!