воскресенье, 29 июня 2014 г.

MongoDB Indexes

Table scan in RDBM
Collection scan in MongoDB

Both are a death for performance


Theory of indexing:
We keep our keys sorted.

Indexes in Mongo db are OrderedList of Keys.

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

Типы идексов в Mongo:

Single Field Indexes
A single field index only includes data from a single field of the documents in a collection. MongoDB supports single field indexes on fields at the top level of a document and on fields in sub-documents.
Compound Indexes
A compound index includes more than one field of the documents in a collection.
Multikey Indexes
A multikey index references an array and records a match if a query includes any value in the array.
Geospatial Indexes and Queries
Geospatial indexes support location-based searches on data that is stored as either GeoJSON objects or legacy coordinate pairs.
Text Indexes
Text indexes supports search of string content in documents.
Hashed Index
Hashed indexes maintain entries with hashes of the values of the indexed field.

Эта отсортированная структура сохраняется на диске и по ней мы намного быстрее найдем ссылку в последовательности полных записей колекции на диске.
Например мы создаем ключ|индекс на поля

name, hear_color, age

На диск у нас сохраняется отсортированый список имен, в каждой ячейке имени хранится отсортированный список цвета волос, а в каждой ячейке цвета волос хранятся отсортированные возраста.
А уже на каждой ячейке возраста хранятся ссылки на целые записи всей колекции.

Logging and Profiling

Логирование медленных запросов

Все логи который больше 100 мс считаются медленными и поэтому логируются монго.

Profiler

Пишутся данные в колекцию system.profile
Существуют три уровня/режима
0 -  Off
1 - Log my slow queries
2 - Log all my queries

Можно сразу запустить mongod в указанном режиме
> mongod -dbpath /usr/local/var/mongodb --profile 1 --slowms 2
Мы указали режим и что меделнными мы считаем запросы от 2-х милисекунд

И вот мы выполнили медленный запрос в базу, и так мы его найдем в наших логах:
> db.system.profile.find().pretty()

Обычно там логов много и не редко из разных баз и с разных колекций, чтобы поискать можно воспользоваться следующими командами:
> db.system.profile.find({ns:/interestedDb.interestedColl/}).sort({ts: 1}).pretty()
Так мы ищем только интересующую нас базы и колекцию в ней, и сортируем по времени их создания Или только какие-то очень медленные с любой колекции и базы:
> db.system.profile.find({millis: {$gt: 500}}).sort({ts: 1}).pretty()


Узнать поточный  режим профайлера:

> db.getProfilingLevel()
1
Узнать что у нас логируется и его дополнительный параметр(например у медленных, что считать медленным):
> db.getProfilingStatus()
{"was": 1, "slowms": 2}


Установка в уже запущенном монго:
> db.setProfilingLevel(1, 4)
{"was": 1, "slowms": 4, "ok": 1}

Mongotop

Аналог юниксового top.
При запуске мы указываем параметром с каким диапазоном времени делать просмотр процессов в запащенном монгод.

Mongostat

Аналог юниксового iostat.


суббота, 28 июня 2014 г.

GeoJSON

Json format для карт.
Типы представляют:
Места
Улицы
Регионы

Наборы мест
Наборы улиц
Наборы регионов


пятница, 27 июня 2014 г.

Как добавить сервис к запуску со стартом системы


ln -sfv /usr/local/opt/rabbitmq/homebrew.mxcl.rabbitmq.plist  ~/Library/LaunchAgents

Запустить новосозданную ссылку сейчас:
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.rabbitmq.plist

четверг, 26 июня 2014 г.

Изучение эфективности запросов, занимаемой памати и другое

Изучение того как был обработан запрос

для этого есть метод курсора .explain(), он выводит следующие пункты:

cursor - если поиск прошел без использования индекса мы увидим DefaultCursor, если с индексом, то мы увидим что-нибудь вроде "BtreeCursor indexfield1_1_indexfield2_1_...indexfieldN_1"

isMultyKey - тру, если в ключ входит поле со значением массива.

n - количество документов, которые вернулись в результате запроса.

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

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

indexOnly - может ли запрос быть удовлетворен только идексом

indexBounds - если у нас поиск идексный, то для каждого поля индекса(для сборного их несколько, для несборного - один) показываются границы сколько минимально может быть просканировано индексов, и сколько максимально -- пока не понятно как это я видет эти два значения равными???

millis - время выполнения запроса в милисекундах.


Когда мы запрашиваем компонентный запрос, например выборка и потом сортировка, то в этой ситуации даже если под выборку не попадет индекс, он может пригодиться в сортировке. Например со следующим индексом, следующие запросы будут использовать индекс:
< db.foo.ensureIndex({a:1, b:1, c:1})

< db.foo.find({a:3})
< db.foo.find({c:1}).sort({a:1, b:1})
Но не:
< db.foo.find({b:3, c:4})
< db.foo.find({c:1}).sort({a:-1, b:1})

Как узнать размер

Размер колекции на диске:
< db.collection.stats()

Не нужно стремиться чтобы вся колекция помещалась у нас в оперативной памяти сервера, но неплохо, чтобы в ней полностью помещались индексы колекций базы.
< db.foo.totalIndexSize()

В результате даже если мы не создавали индекс на колекцию, будет размер обязательного индекса, который создается обязательно для _id.



вторник, 10 июня 2014 г.

Динамика состояния DBCollection

Мы получаем колекцию:
final DBCollection grades = db.getCollection("grades");

Это именно состояние колекции, а не курсор по ней. С него мы получаем информацию о состоянии.

То есть если мы получили ссылку на колекцию и посмотрели например к-во документов в ней:
System.out.println(grades.count());
800;

А потом например удалили некие из нее элементы:
grades.remove(new BasicDBObject(
        "_id",
        new BasicDBObject(
            "$in",
            forDeleteList//List
        )
));
То это не означает что нам нужно делать новую ссылку на колекцию, повторное обращение к методу количества даст новый результат:
System.out.println(grades.count());
600;

понедельник, 9 июня 2014 г.

Hibernate Architecture


С курса хибернейт на сайте плюралсайт.ком.

Spring Data JPA

Этот модуль фреймворка Spring помогает избежать шаблонного кода работы с ЭнтитиМенеджера.

И так Spring Data JPA:
- A wrapper for JPA
  - Need to know JPA before you can use Spring Data JPA
- Replaces our Repository Tier
- Extremely powerful and eliminates boiler plate code
- Can be extended for additional functionality

воскресенье, 8 июня 2014 г.

NamedQueries

- Cleaner than adhoc JPQL
- Not required, but focuses on the domain
- Named parameters


@NamedQueries({ @NamedQuery(name=Goal.FIND_GOAL_REPORTS,
  query="Select new com.domain.model.GoalReport(g.minutes, e.minutes, e.activity) " +
   "from Goal g, Exercise e where g.id = e.goal.id"
)})

Projection

- Great way to present objects to the UI
- Objects added using JPQL syntax
- Projection Objects can be JPA Entities
- Need a constructor for the projection

String jpql="Select new com.domain.model.GoalReport(g.minutes, e.minutes, e.activity) " +
  "from Goal g, Exercise e where g.id = e.goal.id";

Самая распространенная ошибка в приложениях SpringMVC-Hibernate/JPA

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

Проблема решается вот таким веб-фильтром OpenEntityManagerInViewFilter, который обеспечивает жизнь сессии ЭнтитиМенеджера на все время обработки веб-запроса:
<filter>
  <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
  <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
  <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

Join Types and Fetch Type

4 join types:
  - @OneToOne
  - @OneToMany
  - @ManyToOne
  - @ManyToMany

Can be used in various configurations:
  - Unidirectional
  - Bidirectional
  - Cascade


Fetch Types:
  - Lazy - Queries the database when that property is called
  - Eager - Queries the database when the object is originally created
Хибернейт имеет ограничение - он позвояет иметь только две колекции на объект, которые могут быть "нетерпеливо" выбраны в объект.

@OneToMany(mappedBy="goal", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List exercise = new ArrayList<>();



суббота, 7 июня 2014 г.

Fat Arrow

Этот способ позволяет нам ссылаться на this из класса а не контекста более глубокого.
Например:

class Coffee
  constructor: (@name, @strength=1, @inventory=0) ->

  pourClick: ->
    $("#pour-#{@name}").click (event) ->
      if @inventory isnt 0
        @inventory -= 1
        alert "Poured a cup of #{name}"
В даном примере мы хотим внутри хендлера клика обратиться к @inventory (this.inventory) именно инстанции класса, но в данном контексе this будет представлять кнопку.
Именно для такого случая придумали Fat Arrow(=>) чтобы указать, что нас интересует контекст инстанции класса.
class Coffee
  constructor: (@name, @strength=1, @inventory=0) ->

  pourClick: ->
    $("#pour-#{@name}").click (event) =>
      if @inventory isnt 0
        @inventory -= 1
        alert "Poured a cup of #{name}"

пятница, 6 июня 2014 г.

Splat Arguments

Фишка из Ruby, которая помогает в работе с переменным количеством аргументов.
loadTruck = (firstDibs, secondDibs, tooSlow...) ->
    truck:
        driversSeat: firstDibs
        passengerSeat: secondDibs
        trunkBed: tooSlow

loadTruck("Amanda", "Joel")
# => { truck: { driversSeat: "Amanda", passengerSeat: "Joel", trunkBed: [] } }

loadTruck("Amanda", "Joel", "Bob", "Mary", "Phillip")
# => { truck: { driversSeat: "Amanda", passengerSeat: "Joel", trunkBed: ["Bob", "Mary", "Phillip"] } }

With a trailing argument:
loadTruck = (firstDibs, secondDibs, tooSlow..., leftAtHome) ->
    truck:
        driversSeat: firstDibs
        passengerSeat: secondDibs
        trunkBed: tooSlow
    taxi:
        passengerSeat: leftAtHome

loadTruck("Amanda", "Joel", "Bob", "Mary", "Phillip", "Austin")
# => { truck: { driversSeat: 'Amanda', passengerSeat: 'Joel', trunkBed: [ 'Bob', 'Mary', 'Phillip' ] }, taxi: { passengerSeat: 'Austin' } }

loadTruck("Amanda")
# => { truck: { driversSeat: "Amanda", passengerSeat: undefined, trunkBed: [] }, taxi: undefined }

среда, 4 июня 2014 г.

MongoDB mongoimport tool

Утилита для импорта документов в виде джейсона в указанную базу и колекцию.
Формат команды:
mongoimport -d <DATABASE> -c <COLLECTION> < FILE.js

Нужно обратить внимание, что формат файла не json - внутри не массив обьектов, а строки обьектов - можно понять что каждаю строка какбы инсертится в колекцию. 

Подключение Java движка шаблонов Freemarker в приложение


import freemarker.template.Configuration;
import freemarker.template.Template;

public class MyApp {
  public static void main(String[] args) throws Exception {
    Configuration cfg = new Configuration();
    cfg.setClassForTemplateLoading(MyApp.class, "/");//где искать шаблоны фримаркера, мы указываем что искать в корне класспаза

    Template helloTmplt = cfg.getTemplate("hello.ftl");
    StringWriter writer = new StringWriter();

    Map helloMap = new HashMap();
    helloMap.put("name", "Freemarker");

    helloTmplt.process(helloMap, writer);

    System.out.println(writer);
  }
}

А где-то в recources/hello.ftl:
<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Hello ${name}</h1>
</body>
</html>

MongoDB. What is it?

Is:
- NoSQL;
- Document Store (Document Database - key/value pairs, lists are also able to be used);
- Schemaless Database (has dynamic schema);

No:
- joins;
- transactions;
- sql.

Basic usage of mongo client tool:

> db //  посмотреть имя выбраной поточной базы данных
> show dbs // показать имена доступных баз данных
> use mydbname // выбрать базу данных
> show collections // показать доступный коллекции документов в поточной базе данных


mongorestore path/to/dir/with/dumps ## залить в работающую монгу дампы из директории

понедельник, 2 июня 2014 г.

jQuery Promises

$.ajax возвращает промис обьект, этот патерн делает код более читабельным.
var promise = $.ajax('/url',{...});//опции без колбеков success&error
promise.done(function(args){});//callback on success
promise.fail(function(args){});//callback on error

Кроме того, если объект который приходит с удаленки сложной структуры, а нам из нее необходима только некая часть, мы можем руками создать обьект промиса и запонить его в колбеках аякса только нужными частями ответа, так мы можем написать максимально простой обработчик в промисе, но приэтом по закону мировоздания более сложными будут опции аякса:)
var promise = $.Deferred();
$.ajax('/weather', {
    data: {q: location},
    success: function(result){
      promise.resolve(result.weather);
    },
    error: function(){
      var error = 'invalid location';
      promise.reject(error);
    }
});
promise.done(function(args){});//callback on success
promise.fail(function(args){});//callback on error



ajax запросы заканчиваются в разное время, бывают моменты, когда процессинг ответов на разные запросы нужно произвести в одно и тоже время. Для этого ипользуются $.when & $.then





$.when(
     Weather.today(loc),
     City.find(loc)
   ).then(function(weatherResult, cityResult){
     resultsDiv.append(cityResult);
     resultsDiv.append(weatherResult);

jQuery прояснение моментов

Axaj

$.ajax('/url/to/server/script', {
  ...
  dataType: 'json', // сразу попытаться распарсить ответ как json(по умолчанию jQuery делает анализ)
  contentType: 'application/json', //jQuery устанавливает соответствующий хттп заголовок, на основании которого сервер может принимать решение в каком формате отвечать
  context: someWidgetEl, //в колбеках this будет ссылаться на указанный обьект 
  data: $('form').serialize(), //так мы собираем значение полей с формы в джейсон
  
});