2015-11-12 2 views
2

Я понял, что использование базы данных SQL (Postgres) является одним из наиболее эффективных способов переноса моих реляционных данных (40+ GB через 24 файла CSV) в Elasticsearch с помощью nested structure. Однако у меня по-прежнему возникают проблемы с форматированием вывода JSON из Postgres: 1) нежелательные линии (\ n), 2) нежелательная строка заголовка и 3) нежелательный формат даты. нет Вот простой пример, чтобы продемонстрировать:Форматирование Postgres Выход JSON для вложенной структуры Elasticsearch

file1 
id,age,gender,wave 
1,49,M,1 
2,72,F,0 

file2 
id,time,event1 
1,2095-04-20 12:28:55,V39 
1,2095-04-21 2:27:45,T21 
2,2094-05-17 18:17:25,V39 

file3 
id,time,event2 
1,2095-04-22 3:48:53,P90 
2,2094-05-18 1:28:23,RT4 
2,2094-05-18 4:23:53,W3 

после добавления этих томов CSV для схемы с именем форума и запустив SQL кода:

with f_1 as(
    SELECT id, json_agg(file1.*) AS tag 
    FROM forum.file1 
    GROUP BY id 
), f_2 as (
    SELECT id, json_agg(file2.*) AS tag 
    FROM forum.file2 
    GROUP BY id 
), f_3 as (
    SELECT id, json_agg(file3.*) AS tag 
    FROM forum.file3 
    GROUP BY id 
) 
SELECT ('{"id":' || a.id), ('"file1":' || a.tag), ('"file2":' || b.tag), ('"file3":' || c.tag ||'}') 
FROM f_1 AS a, f_2 AS b, f_3 AS c 
WHERE b.id = a.id AND c.id = a.id; 

Я получаю этот вывод (pgAdminIII - Экспорт в файл - не процитировать):

?column?,?column?,?column?,?column? 
{"id":1,"file1":[{"id":1,"age":49,"gender":"M","wave":1}],"file2":[{"id":1,"time":"2095-04-20T12:28:55","event1":"V39"}, 
{"id":1,"time":"2095-04-21T02:27:45","event1":"T21"}],"file3":[{"id":1,"time":"2095-04-22T03:48:53","event2":"P90"}]} 
{"id":2,"file1":[{"id":2,"age":72,"gender":"F","wave":0}],"file2":[{"id":2,"time":"2094-05-17T18:17:25","event1":"V39"}],"file3":[{"id":2,"time":"2094-05-18T01:28:23","event2":"RT4"}, 
{"id":2,"time":"2094-05-18T04:23:53","event2":"W3"}]} 

Вы можете видеть, что для данного идентификатора есть данные на нескольких строках. Мне нужно, чтобы все данные находились в одной строке для заданного id (т. Е. No \ n). Пара других второстепенных проблем, на которые я не потратил много времени, но хотел бы изменить, - это первая строка, которая не нужна, я бы хотел избавиться от ?column?,?column?,?column?,?column?, не открывая файл после его обработки. В идеале я также предпочел бы, чтобы в выходной дате не было T. Я должен уметь разместить T в Elasticsearch, но до сих пор не получил его, чтобы принять его. Это выход я хочу от Postgres, который работает для ввода в Elasticsearch (с использованием stream2es и вложенную структуру отображения):

{"id":1,"file1":[{"id":1,"age":49,"gender":"M","wave":1}],"file2":[{"id":1,"time":"2095-04-20 12:28:55","event1":"V39"},{"id":1,"time":"2095-04-21 02:27:45","event1":"T21"}],"file3":[{"id":1,"time":"2095-04-22 03:48:53","event2":"P90"}]} 
{"id":2,"file1":[{"id":2,"age":72,"gender":"F","wave":0}],"file2":[{"id":2,"time":"2094-05-17 18:17:25","event1":"V39"}],"file3":[{"id":2,"time":"2094-05-18 01:28:23","event2":"RT4"},{"id":2,"time":"2094-05-18 04:23:53","event2":"W3"}]} 

Добавление to_json не фиксирует нежелательную линию ленты, но это добавляет \" вместо " которые в stream2es синтаксический анализатор не любит:

SELECT to_json('{"id":' || a.id), to_json('"file1":' || a.tag::json), to_json('"file2":' || b.tag::json), to_json('"file3":' || c.tag::json ||'}')

"{\"id\":1","\"file1\":[{\"id\":1,\"age\":49,\"gender\":\"M\",\"wave\":1}]" ...

es2stream excep : Exception in thread "stream dispatcher" java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IPersistentMap

ответ

1

Выбрать все в одной колонке (вместо четырех). Функция format() поможет вам записать ее более четко. Используйте

regexp_replace (str, '(\d\d\d\d-\d\d-\d\d)T', '\1 ', 'g') 

исправить формат даты и

replace (str, e' \n ', '') 

пропустить новой строки символов.

Использование COPY command упростить вопрос:

COPY (
    with f_1 as(
     SELECT id, json_agg(file1.*) AS tag 
     FROM forum.file1 
     GROUP BY id 
    ), f_2 as (
     SELECT id, json_agg(file2.*) AS tag 
     FROM forum.file2 
     GROUP BY id 
    ), f_3 as (
     SELECT id, json_agg(file3.*) AS tag 
     FROM forum.file3 
     GROUP BY id 
    ) 
    SELECT 
     replace(
      regexp_replace(
       format('{"id":%s,"file1":%s,"file2":%s,"file3":%s}', 
        a.id, a.tag, b.tag, c.tag), 
       '(\d\d\d\d-\d\d-\d\d)T', '\1 ', 'g'), 
      e' \n ', '') 
    FROM f_1 AS a, f_2 AS b, f_3 AS c 
    WHERE b.id = a.id AND c.id = a.id 
) TO '/full/path/to/your/file'; 

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

create or replace function format_data_line(command text, data_str text) 
returns setof text language plpgsql as $$ 
begin 
    return next command; 
    return next    
     replace(
      regexp_replace(data_str, 
       '(\d\d\d\d-\d\d-\d\d)T', '\1 ', 'g'), 
      e' \n ', ''); 
end $$; 

COPY (
    with f_1 as(
     SELECT id, json_agg(file1.*) AS tag 
     FROM forum.file1 
     GROUP BY id 
    ), f_2 as (
     SELECT id, json_agg(file2.*) AS tag 
     FROM forum.file2 
     GROUP BY id 
    ), f_3 as (
     SELECT id, json_agg(file3.*) AS tag 
     FROM forum.file3 
     GROUP BY id 
    ) 
    SELECT 
     format_data_line(
      'my command', 
      format('{"id":%s,"file1":%s,"file2":%s,"file3":%s}', 
       a.id, a.tag, b.tag, c.tag)) 
    FROM f_1 AS a, f_2 AS b, f_3 AS c 
    WHERE b.id = a.id AND c.id = a.id 
) TO '/full/path/to/your/file'; 
+0

Это похоже на то, что я просил, спасибо! Однако stream2es, кажется, ломается, когда я пишу в большом файле. Поэтому я планирую вернуться к использованию [Bulk API] (https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html). Для этого мне нужно добавить командную строку ({command} \ n) над каждой линией данных.Я пытаюсь выяснить, как добавить разрывы строк к приведенному выше, но не повезло (форматирование E '\ n' и 'standard_conforming_strings' вводят \ n как фактические строки, которые не распознаются как линейные каналы). – bjg

+0

См. Отредактированный ответ. – klin

+0

Еще раз спасибо! К сожалению, в моем примере не было случая, когда данный объект может отсутствовать в файле. Использование структуры выше этого позволит устранить их из-за 'AND''s. Я понял, как использовать 'LEFT OUTER JOIN' вместо' WHERE', чтобы облегчить это, но оставшаяся строка из инструкции формата является проблемой. Например, если вы исключили две строки для «id 1» из файла file2.csv, то вывод будет выдавать '' file2 ":" file3 ": [{" id ": 1,' is not valid. Я попытался заставить «file2»: {}, «file3» в случае NULL, но не могу заставить его работать с CASE или COALESE. – bjg

Смежные вопросы