Alisson Machado
24 November 2016

Sincronizando dados do PostgreSQL no Elasticsearch

Atualmente estou com uma missão de gerar relatórios e estatísticas com os dados do Moodle, porém o Moodle trabalha somente com bancos de dados relacionais como PostgreSQL e MySQL e o ambiente que vou analisar terá cerca de 6 mil usuários, uma hora ou outra as consultas para relatórios vão ficar lentas. Tendo este cenário em vista, estou fazendo uma sincronização dos dados do PostgreSQL para o Elasticsearch.


Como o Elasticserach é um banco de dados noSQL as buscas realizadas nele em grandes volumes de dados são extremamente mais rápidas se comparadas à qualquer banco de dados relacional. Então nas linhas abaixo vou mostrar como é possível fazer essa migração. A primeira parte é fazer a instalação do java versão 8. Para fazer isso execute os seguintes passos abaixo.

echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu xenial main" | tee /etc/apt/sources.list.d/webupd8team-java.list
echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu xenial main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
apt-get update
apt-get install oracle-java8-installer


Caso você queira deixa-lo como padrão, que foi o que eu fiz, execute a instrução abaixo.

apt-get install oracle-java8-set-default -y


Uma vez com o java instalado, vamos instalar o ElasticSearch e o Logstash.

apt-get -f install logstash elasticsearch -y


Para fazer a sincronização do PostgreSQL com o Logstash é necessário instalar um plugin chamado: logstash-input-jdbc. A instalação é feita seguindo as seguintes instruções:

cd /usr/share/logstash/bin
./logstash-plugin install logstash-input-jdbc


Quando terminada a instalação é necessário baixar o drive do PostgreSQL para Java, pois esse plugin precisa desse driver para conectar ao postgres. O driver pode ser baixado em qualquer diretório do linux, mas nas instruções abaixo eu coloquei dentro do diretório do próprio logstash.

cd /usr/share/logstash
wget https://jdbc.postgresql.org/download/postgresql-9.4.1212.jre6.jar


Agora é hora de criar o arquivo de configuração que vai fazer essa sincronização, para isso siga as instruções abaixo:

 cd /etc/logstash/conf.d/
vim moodle-courses-index.conf


Agora dentro desse arquivo coloque o seguinte conteúdo:

input {
    jdbc {
        jdbc_connection_string => "jdbc:postgresql://localhost:5432/moodle"
        jdbc_driver_library => "/usr/share/logstash/postgresql-9.4.1212.jre6.jar"
        jdbc_user => "moodle_db_admin"
        jdbc_password => "moodle_db_pass"
        jdbc_driver_class => "org.postgresql.Driver"
        statement => "SELECT * from mdl_course"
    }
}
output {
    elasticsearch {
             index => "moodle"
             document_type => "mdl_course"
             document_id => "%{id}"
             hosts => ["127.0.0.1"]
        }
}


Na seção input desse arquivo são definidos os parâmetros de conexão com o banco de dados relacional. A parte mais importante é o statement pois é nela em que você define que tabela você vai sincronizar com o ElasticSearch. Na seção output são definidos os parâmetros de saída, ou seja, para onde serão enviados os dados do PostgreSQL.


Nessa parte foi definido que será criado um índice chamado moodle, e nele será criado um documento chamado mdl_course que é o mesmo nome da tabela e cada documento será um registro da tabela. document_id você deve colocar o campo id da sua tabela, pois ele será o mesmo id em que você fará a busca no ElasticSearch. hosts é o endereço do host onde está instalado o seu ElasticSearch. Salve esse arquivo e agora para fazer a importação desses dados siga as instruções abaixo:

cd /usr/share/logstash
./bin/logstash -f /etc/logstash/conf.d/moodle-courses-index.conf


E a saída do comando será parecida com essa:

WARNING: Could not find logstash.yml which is typically located in $LS_HOME/config or /etc/logstash. You can specify the path using --path.settings. Continuing using the defaults
Could not find log4j2 configuration at path /usr/share/logstash/config/log4j2.properties. Using default config which logs to console
17:25:59.515 [[main]{:removed=>[], :added=>["http://127.0.0.1:9200"]}}
17:26:00.211 [[main]-pipeline-manager] INFO  logstash.outputs.elasticsearch - Using mapping template from {:path=>nil}
17:26:00.634 [[main]-pipeline-manager] INFO  logstash.outputs.elasticsearch - Attempting to install template {:manage_template=>{"template"=>"logstash-*", "version"=>50001, "settings"=>{"index.refresh_interval"=>"5s"}, "mappings"=>{"_default_"=>{"_all"=>{"enabled"=>true, "norms"=>false}, "dynamic_templates"=>[{"message_field"=>{"path_match"=>"message", "match_mapping_type"=>"string", "mapping"=>{"type"=>"text", "norms"=>false}}}, {"string_fields"=>{"match"=>"*", "match_mapping_type"=>"string", "mapping"=>{"type"=>"text", "norms"=>false, "fields"=>{"keyword"=>{"type"=>"keyword"}}}}}], "properties"=>{"@timestamp"=>{"type"=>"date", "include_in_all"=>false}, "@version"=>{"type"=>"keyword", "include_in_all"=>false}, "geoip"=>{"dynamic"=>true, "properties"=>{"ip"=>{"type"=>"ip"}, "location"=>{"type"=>"geo_point"}, "latitude"=>{"type"=>"half_float"}, "longitude"=>{"type"=>"half_float"}}}}}}}}
17:26:00.642 [[main]-pipeline-manager] INFO  logstash.outputs.elasticsearch - New Elasticsearch output {:class=>"LogStash::Outputs::ElasticSearch", :hosts=>["127.0.0.1"]}
17:26:00.645 [[main]-pipeline-manager] INFO  logstash.pipeline - Starting pipeline {"id"=>"main", "pipeline.workers"=>4, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>5, "pipeline.max_inflight"=>500}
17:26:00.652 [[main]-pipeline-manager] INFO  logstash.pipeline - Pipeline main started
17:26:01.298 [Api Webserver] INFO  logstash.agent - Successfully started Logstash API endpoint {:port=>9600}
17:26:03.677 [LogStash::Runner] WARN  logstash.agent - stopping pipeline {:id=>"main"}


Se não aparecer nenhum ERROR ai no meio quer dizer que funcionou. Para testar você pode fazer um request na api do ElasticSearch e ver se os dados estão lá, no meu caso vou buscar pelo ID 85.

root@alisson-pc:/usr/share/logstash# curl http://localhost:9200/moodle/mdl_course/85/?pretty


{
  "_index" : "moodle",
  "_type" : "mdl_course",
  "_id" : "85",
  "_version" : 2,
  "found" : true,
  "_source" : {
    "groupmode" : 0,
    "idnumber" : "",
    "cacherev" : 1480009744,
    "summaryformat" : 1,
    "showreports" : 1,
    "startdate" : 1479866400,
    "completionnotify" : 0,
    "defaultgroupingid" : 0,
    "showgrades" : 1,
    "@version" : "1",
    "sortorder" : 10001,
    "theme" : "",
    "id" : 85,
    "lang" : "",
    "summary" : "",
    "visible" : 1,
    "format" : "onetopic",
    "visibleold" : 1,
    "groupmodeforce" : 0,
    "shortname" : "Enfermagem",
    "legacyfiles" : 0,
    "enablecompletion" : 1,
    "tags" : [ ],
    "calendartype" : "",
    "newsitems" : 3,
    "requested" : 0,
    "timecreated" : 1479832086,
    "@timestamp" : "2016-11-24T19:26:00.669Z",
    "marker" : 0,
    "timemodified" : 1479832940,
    "maxbytes" : 0,
    "fullname" : "Enfermagem",
    "category" : 1
  }
}


É isso ai, falows \o