首页 > 代码库 > Elasticsearch PHP MYSQL的同步使用

Elasticsearch PHP MYSQL的同步使用

简介与用途

Elasticsearch是一个分布式,RESTful模式的高速搜索引擎,它使用标准的RESTful APIs和JSON,同时提供支持如java,python,php等的多种语言。下文将Elasticsearch简称ES。

一个简单的curl查询数据的示例如下:

curl -XGET ‘localhost:9200/sedoctorfeedback/feedback/_search?pretty&q=119‘

ES使用诸如XPUT,XDELETE,XPOST,XGET等RESTful模式完成数据的增删改查操作。本例意思是找到sedoctorfeedback索引里type为feedback的数据,查询条件是119,这是全文搜索,fulltext。查询结果如下:

{  "took" : 29,  "timed_out" : false,  "_shards" : {    "total" : 5,    "successful" : 5,    "failed" : 0
  },  "hits" : {    "total" : 1,    "max_score" : 1.386767,    "hits" : [ {      "_index" : "sedoctorfeedback",      "_type" : "feedback",      "_id" : "119",      "_score" : 1.386767,      "_source" : {        "id" : 119,        "content" : "google地图无法正常显示",        "contacttype" : "QQ",        "contact" : "702865206",        "questiontype" : 4,        "seversion" : "5.0.1.9",        "ieversion" : "6",        "osversion" : "win_xp_32",        "img" : 0,        "joindate" : "2012-03-14T00:00:00.000+08:00",        "addtime" : "2012-03-14T15:29:34.000+08:00",        "qid" : "",        "extension1" : "",        "extension2" : "",        "extension3" : ""
      }
    } ]
  }
}

同样,可以使用php查询数据,若使用php语法代码如下:

<?php$params = array();$params[‘hosts‘] = array (   ‘127.0.0.1:9200‘,                 // IP + Port);require ‘vendor/autoload.php‘;$client = new Elasticsearch\Client($params);$params = array(            ‘index‘ => ‘sedoctorfeedback‘,            ‘type‘ => ‘feedback‘,            ‘id‘ => 119,
        );        try {            $resp = $client->get($params);
        } catch (Exception $ex) {            $resp = $ex->getMessage();
        } 
var_dump($resp);

执行php程序返回结果和上例相同。

环境安装

我们的目的是将mysql数据同步到ES,通过php查询ES。需要安装以下依赖

  1. jdk,jdk需要使用1.8版本,如果使用1.7版本会报错。

  2. ES安装,安装ES一定要注意ES的版本,笔者安装的是2.3.2版本

  3. 安装php,php至少为5.3.9版本,否则无法使用ES,笔者安装的是5.6.3版本。

  4. php composer安装,并更改composer的镜像为国内

  5. Elasticsearch-jdbc安装,版本要和ES的版本对应。

1 安装JDK

先检查系统有没有jdk,一般centos会自带jdk,检查如下

$ rpm -qa | grep jdk
java-1.7.0-openjdk-1.7.0.101-2.6.6.4.el6_8.x86_64
java-1.7.0-openjdk-devel-1.7.0.101-2.6.6.4.el6_8.x86_64

centos自带的是1.7版本的jdk,这个不能用,笔者就在这里栽了坑。这时需要先将系统自带的jdk删掉,如下

rpm -e --nodeps java-1.7.0-openjdk-1.7.0.101-2.6.6.4.el6_8.x86_64

到(http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) 选择jdk版本。在选择版本之前先看自己的linux是32位还是64位的,使用uname -a 查看系统版本。

$ uname -a
Linux gz01v.brow.corp.qihoo.net 2.6.32-220.4.2.el6.x86_64 #1 SMP Tue Feb 14 04:00:16 GMT 2012 x86_64 x86_64 x86_64 GNU/Linux

可知笔者系统是64位的,因此选择了如下jdk 技术分享

技术分享

下载得到 jdk-8u121-linux-x64.rpm 安装包,将该文件放到/home/chenxiaolong 目录,并赋予可执行权限。使用rpm安装,命令及过程如下

[root@gz03v /home/chenxiaolong]# rpm -ivh jdk-8u121-linux-x64.rpm Preparing...                ########################################### [100%]
   1:jdk1.8.0_121           ########################################### [100%]Unpacking JAR files...	tools.jar...	plugin.jar...	javaws.jar...	deploy.jar...	rt.jar...	jsse.jar...	charsets.jar...	localedata.jar...[root@gz03v /home/chenxiaolong]# java -versionjava version "1.8.0_121"Java(TM) SE Runtime Environment (build 1.8.0_121-b13)Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)[root@gz03v /home/chenxiaolong]# javac -versionjavac 1.8.0_121

至此,已成功的安装了jdk 1.8版本。RPM安装会自动将java javac加入环境变量。

2 安装Elasticsearch

ES的安装比较简单,首先到官网下载。笔者在(https://www.elastic.co/downloads/past-releases?page=9)下载的是2.3.2版本,因为后面使用elasticsearch-jdbc也是要2.3.2版本。另外使用的php必须是5.3.9或以上版本,因为5.3.8及以下版本存在两个bug,致使php无法使用ES。详情见(https://www.elastic.co/guide/en/elasticsearch/client/php-api/1.0/_php_version_requirement.html)。需要说明的是,不同的elasticsearch php api 需要对应的php版本。ES 5.0版本需要对应的php 5.6.6 及以上版本,ES 2.0 需要php 5.4.0 及以上版本,ES 1.0 需要php 5.3.9及以上版本。不同版本的ES,使用composer安装的依赖包版本也不同,需要与ES的版本对应

在官网下载得到elasticsearch-2.3.2.tar.gz,将该文件包放到/home/chenxiaolong目录,解压文件

[root@gz03v /home/chenxiaolong]# tar zxvf elasticsearch-2.3.2.tar.gz elasticsearch-2.3.2/README.textile
elasticsearch-2.3.2/LICENSE.txt
elasticsearch-2.3.2/NOTICE.txt
elasticsearch-2.3.2/modules/
elasticsearch-2.3.2/modules/lang-groovy/
elasticsearch-2.3.2/modules/reindex/
elasticsearch-2.3.2/modules/lang-expression/
······此处省略······

解压后得到目录elasticsearch-2.3.2,cd到解压后的bin目录下,启动ES

[root@gz03v /home/chenxiaolong]# cd elasticsearch-2.3.2/bin/
[root@gz03v /home/chenxiaolong/elasticsearch-2.3.2/bin]# ./elasticsearch
Exception in thread "main" java.lang.RuntimeException: don‘t run elasticsearch as root.
	at org.elasticsearch.bootstrap.Bootstrap.initializeNatives(Bootstrap.java:93)
	at org.elasticsearch.bootstrap.Bootstrap.setup(Bootstrap.java:144)
	at org.elasticsearch.bootstrap.Bootstrap.init(Bootstrap.java:270)
	at org.elasticsearch.bootstrap.Elasticsearch.main(Elasticsearch.java:35)
Refer to the log for complete error details.

报错是因为ES不允许使用root账户使用,切换到chenxiaolong账户,启动ES。

[root@gz03v /home/chenxiaolong/elasticsearch-2.3.2/bin]# su chenxiaolong[chenxiaolong@gz03v ~/elasticsearch-2.3.2/bin]$ ./elasticsearchlog4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /home/chenxiaolong/elasticsearch-2.3.2/logs/elasticsearch.log (权限不够)

出现以上错误是因为权限不够,切换到root账户,将目录的属主改成chenxiaolong,并赋予权限755,再切换回chenxiaolong。执行./elasticsearch-2.3.2/bin/elasticsearch 启动ES。

[root@gz03v /home/chenxiaolong/elasticsearch-2.3.2]# cd ..[root@gz03v /home/chenxiaolong]# lselasticsearch-2.3.2  elasticsearch-2.3.2.tar.gz
[root@gz03v /home/chenxiaolong]# cd elasticsearch-2.3.2/bin/[root@gz03v /home/chenxiaolong/elasticsearch-2.3.2/bin]# cd ../../[root@gz03v /home/chenxiaolong]# chown -R chenxiaolong.chenxiaolong elasticsearch-2.3.2[root@gz03v /home/chenxiaolong]# chmod -R 755 elasticsearch-2.3.2[root@gz03v /home/chenxiaolong]# su chenxiaolong[chenxiaolong@gz03v ~]$ ./elasticsearch-2.3.2/bin/elasticsearch
[2017-02-24 22:37:11,391][WARN ][bootstrap                ] unable to install syscall filter: seccomp unavailable: requires kernel 3.5+ with CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER compiled in
[2017-02-24 22:37:11,712][INFO ][node                     ] [Erg] version[2.3.2], pid[20305], build[b9e4a6a/2016-04-21T16:03:47Z]
[2017-02-24 22:37:11,712][INFO ][node                     ] [Erg] initializing ...
[2017-02-24 22:37:12,866][INFO ][plugins                  ] [Erg] modules [reindex, lang-expression, lang-groovy], plugins [], sites []
[2017-02-24 22:37:12,904][INFO ][env                      ] [Erg] using [1] data paths, mounts [[/ (/dev/xvde1)]], net usable_space [81.7gb], net total_space [98.4gb], spins? [no], types [ext2]
[2017-02-24 22:37:12,905][INFO ][env                      ] [Erg] heap size [1007.3mb], compressed ordinary object pointers [true]
[2017-02-24 22:37:12,905][WARN ][env                      ] [Erg] max file descriptors [32768] for elasticsearch process likely too low, consider increasing to at least [65536]
[2017-02-24 22:37:16,197][INFO ][node                     ] [Erg] initialized
[2017-02-24 22:37:16,197][INFO ][node                     ] [Erg] starting ...
[2017-02-24 22:37:16,315][INFO ][transport                ] [Erg] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}
[2017-02-24 22:37:16,321][INFO ][discovery                ] [Erg] elasticsearch/VDpJE96fQ024S4cwk0UIPg
[2017-02-24 22:37:19,374][INFO ][cluster.service          ] [Erg] new_master {Erg}{VDpJE96fQ024S4cwk0UIPg}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-join(elected_as_master, [0] joins received)
[2017-02-24 22:37:19,430][INFO ][http                     ] [Erg] publish_address {127.0.0.1:9200}, bound_addresses {127.0.0.1:9200}
[2017-02-24 22:37:19,430][INFO ][node                     ] [Erg] started
[2017-02-24 22:37:19,434][INFO ][gateway                  ] [Erg] recovered [0] indices into cluster_state

出现如上情况表示启动成功,在此界面ES会一直运行,使用Ctrl+C可终止ES进程。如果要将ES作为一个后台进程运行,加参数 -d 即 ./elasticsearch-2.3.2/bin/elasticsearch

可使用 curl ‘http://localhost:9200/?pretty‘ 查看ES是否正确启动。

[chenxiaolong@gz03v ~]$ curl ‘http://localhost:9200/?pretty‘{  "name" : "She-Venom",  "cluster_name" : "elasticsearch",  "version" : {    "number" : "2.3.2",    "build_hash" : "b9e4a6acad4008027e4038f6abed7f7dba346f94",    "build_timestamp" : "2016-04-21T16:03:47Z",    "build_snapshot" : false,    "lucene_version" : "5.5.0"
  },  "tagline" : "You Know, for Search"}

其中cluster_name是集群的名称,这里我们只在一台机器上安装了ES,集群名称可在/home/chenxiaolong/elasticsearch-2.3.2/config/elasticsearch.yml 配置,出现在配置文件的第17行。

13 # ---------------------------------- Cluster -----------------------------------
 14 #
 15 # Use a descriptive name for your cluster:
 16 #
 17 # cluster.name: my-application
 18 #

3 安装PHP

要使用ES,php的版本必须大于等于5.3.9版本。PHP的安装在次不再赘述。下回追加上。

ES 5.0版本需要对应的php 5.6.6 及以上版本,ES 2.0 需要php 5.4.0 及以上版本,ES 1.0 需要php 5.3.9及以上版本。

4 安装php composer

Composer 是 PHP5以上 的一个依赖管理工具。它允许你申明项目所依赖的代码库,它会在你的项目中为你安装他们。 官网(https://getcomposer.org/) 。执行以下命令安装composer

$ php -r "copy(‘https://getcomposer.org/installer‘, ‘composer-setup.php‘);"$ php -r "if (hash_file(‘SHA384‘, ‘composer-setup.php‘) === ‘55d6ead61b29c7bdee5cccfb50076874187bd9f21f65d8991d46ec5cc90518f447387fb9f76ebae1fbbacf329e583e30‘) { echo ‘Installer verified‘; } else { echo ‘Installer corrupt‘; unlink(‘composer-setup.php‘); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink(‘composer-setup.php‘);"

This installer script will simply check some php.ini settings, warn you if they are set incorrectly, and then download the latest composer.phar in the current directory. The 4 lines above will, in order:

  • Download the installer to the current directory

  • Verify the installer SHA-384 which you can also cross-check here

  • Run the installer

  • Remove the installer

如果看不懂,我来翻译下(相信你肯定能看懂),译文如下:

上述脚本将会检查php.ini是否配置正确,然后在当前目录下载最新版的composer.phar,上面4行代码的执行顺序是

  • 在当前目录下载安装包

  • SHA-384检验安装包

  • 执行安装命令

  • 删除安装包(此步骤可省略)

这将会在当前目录下生成一个composer.phar文件。

[chenxiaolong@gz02v /data/htdocs/chenxiaolong]$ php composer.phar
   ______  / ____/___  ____ ___  ____  ____  ________  _____ / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___// /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/Composer version 1.3.2 2017-01-27 18:23:41

安装成功的结果如上面所示。

在当前目录下(你的项目在哪里就把composer.phar复制到哪里)新建一个composer.json文件,文件内容如下:

{
    "require":{
        "elasticsearch/elasticsearch" : "~1.0"
    },
"repositories": {
    "packagist": {
        "type": "composer",
        "url": "https://packagist.phpcomposer.com"
    } }}

require 里是需要加载的依赖包,url是下载依赖包的地址,这里的url填写的是国内镜像,因为国外的总是被墙。接下来在当前目录执行命令 php composer.phar install --no-dev 完成 ES php api的安装,执行完成会在当前目录下生一个vendor目录,vendor目录下有个autoload.php文件,在你自己写的代码中将autoload.php文件require进来即可。在vendor目录下还有其他一些目录。

vendor 目录里文件如下:

autoload.php composer elasticsearch guzzle monolog pimple psr symfony

编写一个php脚本,代码内容如下:

<?php$params = array();$params[‘hosts‘] = array (   ‘127.0.0.1:9200‘,                 // IP + Port//    ‘localhost:9200‘,         // Domain + Port
 //   ‘localhost‘,             // Just Domain
 //   ‘http://localhost‘,                // SSL to localhost);require ‘vendor/autoload.php‘;$client = new Elasticsearch\Client($params);$p = array(            ‘index‘ => ‘company‘,            ‘type‘ => ‘employee‘,            ‘id‘ => 1,            ‘body‘ => array(                ‘uid‘=>11,                ‘name‘=>‘chenxiaolong‘,                 ‘age‘=>‘23 years old‘
              )
        );$resp = $client->index($p);$params = array(            ‘index‘ => ‘company‘,            ‘type‘ => ‘employee‘,            ‘id‘ => 1,
        );        try {            $resp = $client->get($params); 
        } catch (Exception $ex) {            $resp = $ex->getMessage();
        }

var_dump($resp);

执行以上程序示例如下:

[chenxiaolong@gz02v /data/htdocs/chenxiaolong]$ php es.php 
array(6) {  ["_index"]=>
  string(7) "company"
  ["_type"]=>
  string(8) "employee"
  ["_id"]=>
  string(1) "1"
  ["_version"]=>
  int(2)
  ["found"]=>
  bool(true)
  ["_source"]=>
  array(3) {    ["uid"]=>
    int(11)
    ["name"]=>
    string(12) "chenxiaolong"
    ["age"]=>
    string(12) "23 years old"
  }
}

至此,我们已成功的安装了ES-PHP。下一步就是如何将mysql数据同步到ES了。

5 Elasticsearch-jdbc安装 将mysql数据同步到ES

ES-JDBC可到github (https://github.com/jprante/elasticsearch-jdbc) 查看,执行以下命令下载ES-JDBC

wget http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.2.0/elasticsearch-jdbc-2.3.2.0-dist.zip

[chenxiaolong@gz03v ~]$ wget http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.2.0/elasticsearch-jdbc-2.3.2.0-dist.zip--2017-02-24 23:37:14--  http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.2.0/elasticsearch-jdbc-2.3.2.0-dist.zip正在解析主机 xbib.org... 176.28.49.27正在连接 xbib.org|176.28.49.27|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:30414020 (29M) [application/zip]
正在保存至: “elasticsearch-jdbc-2.3.2.0-dist.zip”

下载对应版本,笔者安装的ES是2.3.2版本,故下载ES-JDBC也是2.3.2版本,一定要用对应版本的,否则你可能会遇到坑。这将会下载得到elasticsearch-jdbc-2.3.2.0-dist.zip,解压该文件到当前目录(/home/chenxiaolong)得到 elasticsearch-jdbc-2.3.2.0 。elasticsearch-jdbc-2.3.2.0目录下有两个子目录 lib 和 bin。编写shell脚本,将mysql数据同步到ES。脚本代码如下:

#! /bin/shbin=/data/htdocs/chenxiaolong/elasticsearch-jdbc-2.3.2.0/bin  # ES-JDBC的目录lib=/data/htdocs/chenxiaolong/elasticsearch-jdbc-2.3.2.0/lib
echo ‘{"type" : "jdbc","jdbc": {"elasticsearch.autodiscover":true,"elasticsearch.cluster":"my-application",   # 集群名称,在config/elasticsearch.yml配置"client.transport.sniff":"true","sniffOnConnectionFault":"true","client.transport.ignore_cluster_name":"false","url":"jdbc:mysql://10.16.59.142:3306/sedoctorfeedback", #链接mysql,IP,PORT,DB,确保库名称为sedoctorfeedback"user":"chenxiaolong","password":"chenxiaolong@browser","sql":"select *,id as _id from feedback order by _id", # sql语句"elasticsearch" : {  "host" : "127.0.0.1",  # ES 所在IP,本机就写127.0.0.1即可
  "port" : 9300   # 端口,9300不行的话就试试9200},"index" : "sedoctorfeedback", # 在ES中新的索引名称,自定义"type" : "feedback"  # 在ES中新的type类型,自定义}
}‘| java   -cp "${lib}/*"   -Dlog4j.configurationFile=${bin}/log4j2.xml   org.xbib.tools.Runner   org.xbib.tools.JDBCImporter

保存以上文件为esmysql.sh,并执行,如果执行失败,或者ES里没有查询到同步过来的数据,可以查看日志

$ tailf /data/htdocs/chenxiaolong/logs/jdbc.log

若出现以下这种错误,可能是脚本中elasticsearch.cluster填写错误,或者port端口错误,改成9200 ,9300试试

][pool-3-thread-1] error while processing request: no cluster nodes available, check settings {autodiscover=true, 

client.transport.ignore_cluster_name=false, client.transport.nodes_sampler_interval=5s, 

client.transport.ping_timeout=5s, cluster.name=my-application, flush_interval=5s, host.0=127.0.0.1, 

max_actions_per_request=10000, max_concurrent_requests=4, max_volume_per_request=10mb, name=importer, port=9200, sniff=false}

执行完毕,就将mysql表中数据同步到ES了,就可以用php查询ES获得数据结果了。php查询示例如本文开头述。或使用

curl -XGET ‘localhost:9200/sedoctorfeedback/feedback/_search?pretty&q=*‘

查看导入结果

常见的坑

安装JDK时候,执行java -version错误如下:

$java -version
bash: /usr/local/jdk1.8.0_121//bin/java: cannot execute binary file

网上说这是因为操作系统的位数和JDK的位数不一致导致的,但是笔者都是64位的。网上的解释并不靠谱,这可能是因为你一开始下载的是JDK的tar.gz的包,将它解压到某个目录,然后配置/etc/profile导致的。这时候你用 whereis java 即可找到java命令所在,笔者的解决办法是rpm -e 删掉jdk的rpm包,再找到并删掉jdk的 tar.gz。重新从官网下载rpm,重新rpm -ivh 安装。只有如以下这样才算正确安装了jdk。RPM安装会自动将java javac加入环境变量。

[root@gz02v ~]# whereis javajava: /usr/bin/java /etc/java /usr/lib/java /usr/share/java /usr/share/man/man1/java.1[root@gz02v ~]# cd /usr/bin/[root@gz02v /usr/bin]# ll | grep javalrwxrwxrwx   1 root root          22 Feb 24 15:44 java -> /etc/alternatives/java
lrwxrwxrwx   1 root root          23 Feb 24 15:44 javac -> /etc/alternatives/javac
lrwxrwxrwx   1 root root          25 Feb 24 15:44 javadoc -> /etc/alternatives/javadoc
lrwxrwxrwx   1 root root          32 Feb 24 15:44 javafxpackager -> /etc/alternatives/javafxpackager
lrwxrwxrwx   1 root root          23 Feb 24 15:44 javah -> /etc/alternatives/javah
lrwxrwxrwx   1 root root          23 Feb 24 15:44 javap -> /etc/alternatives/javap
lrwxrwxrwx   1 root root          30 Feb 24 15:44 javapackager -> /etc/alternatives/javapackager
lrwxrwxrwx   1 root root          30 Feb 24 15:44 java-rmi.cgi -> /etc/alternatives/java-rmi.cgi
lrwxrwxrwx   1 root root          24 Feb 24 15:44 javaws -> /etc/alternatives/javaws

笔者当时遇到的问题就是

lrwxrwxrwx 1 root root 22 Feb 24 15:44 java -> /etc/alternatives/java

lrwxrwxrwx 1 root root 23 Feb 24 15:44 javac -> /etc/alternatives/javac

这两个错误导致的cannot execute binary file

使用ES-JDBC脚本导入数据时候,执行 curl -XGET ‘localhost:9200/sedoctorfeedback/feedback/_search?pretty&q=*‘ 返回

{
  "error" : {
    "root_cause" : [ {
      "type" : "index_not_found_exception",
      "reason" : "no such index",
      "resource.type" : "index_or_alias",
      "resource.id" : "sedoctorfeedback",
      "index" : "sedoctorfeedback"
    } ],
    "type" : "index_not_found_exception",
    "reason" : "no such index",
    "resource.type" : "index_or_alias",
    "resource.id" : "sedoctorfeedback",
    "index" : "sedoctorfeedback"
  },
  "status" : 404}

这可能是由于esmysql.sh中的端口或数据库或索引什么的配置有误。





最后,还有非常重要的一环,就是如何实现ES和mysql增量数据的实时同步,这个等我研究深入了再来更新博文,哈哈哈哈


Elasticsearch PHP MYSQL的同步使用