PostgreSQL 与 ElasticSearch 同步

碰到个全文搜索的需求,鉴于上家公司的业务日志查询用的就是 ELK ,效果还不错,所以用 ElasticSearch 做搜索引擎感觉问题不大。由于是针对业务数据做全文搜索,数据存在数据库里,所以将这些数据同步到 ES ,怎么做呢,无非两种方式:一是通过 ES 的 API 进行增删改查,二是通过中间件进行数据全量、增量的同步。很明显 API 的方式比较麻烦,那就试试第二种吧。中间件的方式总共搜了三种方案:

  1. elasticsearch-jdbc
    一个 独立的第三方工具。使用很简单,写个 shell 脚本就行了:

    shell 脚本例子

    这个工具的活跃度也很高,前一天还有人提 issue 。问题是它的版本兼容性:
    目前最高只兼容Elasticsearch2.3.4

    elastic 官方已经把 Elasticsearch、Logstash 、Kibana 版本升级到5.x版本,现在统一是5.2.2,这和以前的2.x在插件机制上有一些差异,个人倾向于使用最新版,所以这个工具暂时放弃了。

  2. logstash-input-jdbc
    logstash 的一个jdbc 插件,ruby 写的,据说不太好装,logstash 印象里一直是做日志文件收集的,尤其我们的数据库不是常见的 mysql、oracle,而是 postgresql ,感觉趟这个坑的人不多,没信心一定能成功。

  3. PostgreSQL 的 ElasticSearch 同步插件
    直接用 PostgreSQL 的插件,国内 PG 的大牛德哥在云栖社区贴了篇文章《PostgreSQL内核扩展之 - ElasticSearch同步插件》,写的很详细,显然这个方案跑通过了,所以就选了这个方案。

因为这个方案涉及了很多安装步骤,中间出现了很多坑,所以单独写篇文章记录一下,能让后来者少走些弯路吧。

安装前准备

Mac 平台
数据库:PostgreSQL 9.5.4
数据库客户端:pgAdmin 4
Python 2.7.10

安装并运行 ElasticSearch

官网下载 ElasticSearch ,解压缩,以下命令运行:

bin/elasticsearch

安装 PostgreSQL 插件 multicorn

github下载 Multicorn:

git clone https://github.com/Kozea/Multicorn /tmp/multicorn
cd $_

由于 Multicorn 的 master 代码在 OS X 环境有问题,有几个步骤要手工执行:
1.修改文件 Makefile 的93行,将 darwin 的首字母改成大写:Darwin
2.执行 make
3.sudo ARCHFLAGS="-arch x86_64" make install
具体原因看这个issue里的解释
4.执行 make install

pg 数据库中新建一个 EXTENSION

psql -h {ip} -p {port} -d {database} -U {username}
-- 新建名为 multicorn 的 EXTENSION
create extension multicorn ;

安装 PostgreSQL 插件 pg-es-fdw

github 下载 pg-es-fdw:

git clone https://github.com/Mikulas/pg-es-fdw /tmp/pg-es-fdw
cd $_
sudo python setup.py install

基于 multicorn 创建 foreign server

CREATE SERVER multicorn_es FOREIGN DATA WRAPPER multicorn
OPTIONS (
  wrapper 'dite.ElasticsearchFDW'
);

PostgreSQL 的建 server 的语法不再赘述。wrapper 的值 dite.ElasticsearchFDW 的定义就在 pg-es-fdw 插件的 dite 目录 __init__.py 文件里,有兴趣的可以看看。

创建测试表

CREATE TABLE articles (
    id serial PRIMARY KEY,
    title text NOT NULL,
    content text NOT NULL,
    created_at timestamp
);

创建外部表

CREATE FOREIGN TABLE articles_es (
    id bigint,
    title text,
    content text
) SERVER multicorn_es OPTIONS (host '127.0.0.1', port '9200', node 'test', index 'articles');

参数 host 和 port 是 elasticsearch 服务的主机和端口号,参数 node 表示对应的 ES 中的索引名是 test ,参数 index 表示对应的 ES 中的类型名是 articles 。所以对应的 ES 中该表下的数据 url 访问路径是:
http://localhost:9200/test/articles/{id}

创建触发器

对实体表,创建触发器函数,在用户对实体表插入,删除,更新时,通过触发器函数自动将数据同步到对应ES的外部表。同步过程调用 FDW 的接口,对 ES 进行索引的建立,更新,删除:

CREATE OR REPLACE FUNCTION index_article() RETURNS trigger AS $def$
    BEGIN
        INSERT INTO articles_es (id, title, content) VALUES
            (NEW.id, NEW.title, NEW.content);
        RETURN NEW;
    END;
$def$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION reindex_article() RETURNS trigger AS $def$
    BEGIN
        UPDATE articles_es SET
            title = NEW.title,
            content = NEW.content
        WHERE id = NEW.id;
        RETURN NEW;
    END;
$def$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION delete_article() RETURNS trigger AS $def$
    BEGIN
        DELETE FROM articles_es a WHERE a.id = OLD.id;
        RETURN OLD;
    END;
$def$ LANGUAGE plpgsql;

CREATE TRIGGER es_insert_article
    AFTER INSERT ON articles
    FOR EACH ROW EXECUTE PROCEDURE index_article();

CREATE TRIGGER es_update_article
    AFTER UPDATE OF title, content ON articles
    FOR EACH ROW
    WHEN (OLD.* IS DISTINCT FROM NEW.*)
    EXECUTE PROCEDURE reindex_article();

CREATE TRIGGER es_delete_article
    BEFORE DELETE ON articles
    FOR EACH ROW EXECUTE PROCEDURE delete_article();

测试验证

插入一条表记录:

insert into articles(title, content) values ('测试内容1', '测试标题1');

查询 ES ,检查数据是否已同步:

curl 'localhost:9200/test/articles/_search?q=*:*&pretty'

结果如下:


验证同步 ES 的结果

提醒

之前部署这个还踩了个坑,发现 PG 数据库的数据在 ES 中一直没有,原来因为我给elasticsearch安装了x-pack插件,导致给es添加了默认的安全机制,而pg-es-fdw插件中却没有传递访问es的用户名密码,所以一直不通。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • About:PostgreSQL About 《PostgreSQL 源码分析系列》 PostgreSQL 源码分...
    ty4z2008阅读 8,134评论 1 40
  • Linux-Server-Notes PMS /home/softwareluke/图片/2017-09-11 0...
    燕京博士阅读 558评论 0 1
  • 概述 监控预警平台, eagle + eye (鹰眼)的合体词, 寓意可以快速发现问题, 并及时作出响应,Eagl...
    Kungfu猫熊阅读 7,333评论 0 52
  • 谁没有过被出轨,毕竟出轨的人那么多,那么对方就是那个被出轨的。 在一部《匆匆那年》里,方茴和陈寻两个初恋者真...
    Dflorer阅读 228评论 0 0
  • 当我经过溪边 一片枯萎的棕竹叶轰地落下 一条小鱼划过水面 几只青蛙在远处汩汩地叫着 ...
    明心M阅读 256评论 0 2