elasticsearch + elasticsearch-analysis-ik + elasticsearch-jdbc搭建中文搜索引擎
一、背景
1.1、中文分词使用ik,配合elasticsearch-jdbc 2.3.4.1(最高版本)支持的最高版本Elasticsearch 2.3.4,ik选择使用1.9.4 是目前现成的最高版本。
1.2、java环境要求java8
1.3、安装包
1 elasticsearch官网下载 https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/2.3.4/elasticsearch-2.3.4.tar.gz 2 elasticsearch-analysis-ik下载 https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v1.9.4/elasticsearch-analysis-ik-1.9.4.zip 3 elasticsearch-jdbc下载 http://xbib.org/repository/org/xbib/elasticsearch/importer/elasticsearch-jdbc/2.3.4.1/elasticsearch-jdbc-2.3.4.1-dist.zip
二、安装部署
2.1、搭建elasticsearch搜索程序
tar zxvf elasticsearch-2.3.4.tar.gz && mv elasticsearch-2.3.4 /usr/local/elasticsearch
2.1.1 进入es目录
cd /usr/local/elasticsearch
2.1.2 es配置文件
cat /usr/local/elasticsearch/config/elasticsearch.yml |egrep -v '^$|#'
cluster.name: my-application #集群名称 node.name: node-1 #集群节点 network.host: 192.168.1.100 #允许访问的网卡 192.168.1.100 为内网网卡 0.0.0.0为所有网卡 (如果作为生产环境中文搜索 最好只允许内网访问 同时限制ip访问 以防外网任意修改索引) http.port: 9200 #启动端口 http.cors.enabled: true #允许head启动 http.cors.allow-origin: "*" #允许head启动 index.analysis.analyzer.ik.type: "ik" #默认ik分词搜索
2.1.3 添加elasticsearch用户 elasticsearch默认不允许root用户启动
groupadd ela && useradd -g ela ela
2.1.4 启动elasticsearch程序
su - ela #切换到ela用户 root启动会报错
chown -R ela.ela /usr/local/elasticsearch 给ela目录权限
1 ./bin/elasticsearch 前台启动程序 2 ./bin/elasticsearch -d 后台启动程序
注:如果报ERROR: bootstrap checks failed 和 max file descriptors [4096] for elasticsearch process likely too low, increase to at least [65536]错误以及max number of threads [1024] for user [lishang] likely too low, increase to at least [2048]错误,切换到root用户在limit.conf添加修改以下内容
vi /etc/security/limits.conf
* soft nofile 65536 * hard nofile 131072 * soft nproc 2048 * hard nproc 4096
更多报错可参考 http://blog.csdn.net/liangzhao_jay/article/details/56840941 和 http://blog.csdn.net/qq942477618/article/details/53414983
2.1.5 关闭elasticsearch程序
ps -ef|grep elasticsearch www 5963 1 0 Jan15 ? 00:10:34 /usr/local/jdk1.8.0_66/bin/java -Xms256m -Xmx1g -Djava.awt.headless=true
找到对应的pid 5963
kill -9 5963
或者
curl -XPOST http://192.168.1.100:9200/_cluster/nodes/_shutdown
2.1.6 添加elasticsearch-head插件
#在Elasticsearch目录下
/bin/plugin install mobz/elasticsearch-head
重启elasticsearch程序后即可访问
http://192.168.1.100:9200/_plugin/head/
注:因为该插件可以对数据进行,增删改查。故生产环境尽量不要使用,如果要使用,最少要限制IP地址。尽量不要使用。
2.2 搭建elasticsearch-analysis-ik分词
unzip /usr/local/src/elasticsearch-analysis-ik-1.9.4.zip && mv /usr/local/src/elasticsearch-analysis-ik-1.9.4 /usr/local/elasticsearch/plugins/ik
2.2.1 配置elasticsearch.yml,添加ik配置(前面已经添加),保存后重启elasticsearch。
index.analysis.analyzer.ik.type: "ik"
2.2.2 ik分词验证(默认ik_max_word 最细粒度拆分)
curl -XPOST 'http://192.168.1.100:9200/_analyze?analyzer=ik&pretty=true' -d '{"text":"我爱我国"}'
验证结果
{ "tokens" : [ { "token" : "我", "start_offset" : 0, "end_offset" : 1, "type" : "CN_CHAR", "position" : 0 }, { "token" : "爱我", "start_offset" : 1, "end_offset" : 3, "type" : "CN_WORD", "position" : 1 }, { "token" : "我国", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 2 } ] }
使用ik_smart模式 (最粗粒度拆分)
curl -XPOST 'http://192.168.1.247:9200/_analyze?analyzer=ik_smart&pretty=true' -d '{"text":"我爱我国"}'
验证结果
{ "tokens" : [ { "token" : "我", "start_offset" : 0, "end_offset" : 1, "type" : "CN_CHAR", "position" : 0 }, { "token" : "爱", "start_offset" : 1, "end_offset" : 2, "type" : "CN_CHAR", "position" : 1 }, { "token" : "我国", "start_offset" : 2, "end_offset" : 4, "type" : "CN_WORD", "position" : 2 } ] }
2.2.3 搜索测试
2.2.3.1 创建index
curl -XPUT http://192.168.1.100:9200/index
2.2.3.2 创建mapping
curl -XPOST http://localhost:9200/index/fulltext/_mapping -d' { "properties": { "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } }'
2.2.3.3 创建type
curl -XPOST http://192.168.1.100:9200/index/fulltext/1 -d' {"content":"美国留给伊拉克的是个烂摊子吗"}'
curl -XPOST http://192.168.1.100:9200/index/fulltext/2 -d' {"content":"公安部:各地校车将享最高路权"}'
curl -XPOST http://192.168.1.100:9200/index/fulltext/3 -d' {"content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船"}'
curl -XPOST http://192.168.1.100:9200/index/fulltext/4 -d' {"content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首"}'
2.2.3.4 高亮查询
curl -XPOST http://192.168.1.100:9200/index/fulltext/_search -d' { "query" : { "match" : { "content" : "中国" }}, "highlight" : { "pre_tags" : ["<tag1>", "<tag2>"], "post_tags" : ["</tag1>", "</tag2>"], "fields" : { "content" : {} } } }'
2.2.3.5 查询结果
1 { 2 "took": 14, 3 "timed_out": false, 4 "_shards": { 5 "total": 5, 6 "successful": 5, 7 "failed": 0 8 }, 9 "hits": { 10 "total": 2, 11 "max_score": 2, 12 "hits": [ 13 { 14 "_index": "index", 15 "_type": "fulltext", 16 "_id": "4", 17 "_score": 2, 18 "_source": { 19 "content": "中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首" 20 }, 21 "highlight": { 22 "content": [ 23 "<tag1>中国</tag1>驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首 " 24 ] 25 } 26 }, 27 { 28 "_index": "index", 29 "_type": "fulltext", 30 "_id": "3", 31 "_score": 2, 32 "_source": { 33 "content": "中韩渔警冲突调查:韩警平均每天扣1艘中国渔船" 34 }, 35 "highlight": { 36 "content": [ 37 "均每天扣1艘<tag1>中国</tag1>渔船 " 38 ] 39 } 40 } 41 ] 42 } 43 }
2.2.4 热更新IK分词
分词词库配置文件
cat /usr/local/elasticsearch/plugins/ik/config/IKAnalyzer.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 扩展配置</comment> <!--用户可以在这里配置自己的扩展字典 --> <entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry> <!--用户可以在这里配置自己的扩展停止词字典--> <entry key="ext_stopwords">custom/ext_stopword.dic</entry> <!--用户可以在这里配置远程扩展字典 --> <!-- <entry key="remote_ext_dict">words_location</entry> --> <!--用户可以在这里配置远程扩展停止词字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>
热更新 IK 分词使用方法 目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置
<!--用户可以在这里配置远程扩展字典 --> <entry key="remote_ext_dict">location</entry> <!--用户可以在这里配置远程扩展停止词字典--> <entry key="remote_ext_stopwords">location</entry>
其中 location 是指一个 url,比如 http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新了,不需要再重启 ES 实例。
1、该 http 请求需要返回两个头部(header),一个是 Last-Modified,一个是 ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。
2、该 http 请求返回的内容格式是一行一个分词,换行符用 \n 即可。
可以将需自动更新的热词放在一个 UTF-8 编码的 .txt 文件里,放在 nginx 或其他简易 http server 下,当 .txt 文件修改时,http server 会在客户端请求该文件时自动返回相应的 Last-Modified 和 ETag。可以另外做一个工具来从业务系统提取相关词汇,并更新这个 .txt 文件。
2.3 安装jdbc插件
unzip /usr/local/src/elasticsearch-jdbc-2.3.4.1-dist.zip && mv /usr/local/src/elasticsearch-jdbc-2.3.4.1 /usr/local/elasticsearch/jdbc
2.3.1 创建连接脚本
mkdir -P /usr/local/elasticsearch/jdbc/scripts/shell #创建脚本存放目录
mkdir -P /usr/local/elasticsearch/jdbc/scripts/logs #jdbc日志目录
脚本内容
cat mysql_import_es.sh
#!/bin/bash bin=/usr/local/elasticsearch/jdbc/bin lib=/usr/local/elasticsearch/jdbc/lib echo '{ "type":"jdbc", "jdbc":{ "url":"jdbc:mysql://192.168.1.101:3306/testindex", "useSSL" : "false", "user":"root", "password":"test", "cluster": "my-application", "statefile" : "statefile-tag.json", "schedule" : "0/10 0-59 0-23 ? * *", "sql" : [ { "statement" : "SELECT g.goods_id as _id,g.store_id,g.goods_name,g.cate_id,s.state from wl_goods g LEFT JOIN wl_store s on g.store_id=s.store_id where (select from_unixtime(g.last_update)) > ?", "parameter" : [ "$metrics.lastexecutionstart" ] } ], "elasticsearch" : { "cluster" : "my-application", "host" : "0.0.0.0", "port" : 9300 }, "index" : "testindex", "type" : "testtype", "index_settings" : { "analysis" : { "analyzer" : { "ik" : { "tokenizer" : "ik" } } } }, "type_mapping" :{ "testindex": { "properties": { "g.goods_id":{ "type":"integer", "index":"not_analyzed" }, "g.goods_name":{ "type":"string", "analyzer" : "ik_smart" }, "g.store_id":{ "type":"integer", "index":"not_analyzed" }, "g.cate_id":{ "type":"integer", "index":"not_analyzed" },"s.state":{ "type":"integer", "index":"not_analyzed" } } } } } }' | java \ -cp "${lib}/*" \ -Dlog4j.configurationFile=${bin}/log4j2.xml \ org.xbib.tools.Runner \ org.xbib.tools.JDBCImporter
注:执行SQL语句 原始表中要有时间更新字段 如 goods 表中的last_update 因为是时间戳用select from_unixtime(g.last_update) 命令转成时间格式
SELECT g.goods_id as _id,g.store_id,g.goods_name,g.last_update,g.cate_id,s.state from goods g LEFT JOIN store s on g.store_id=s.store_id;
查询所得的表的结果
_id | store_id | goods_name | last_update | cate_id | state |
1 | 87 | 磨豆机 电动咖啡研磨机 家用 咖啡机磨咖啡豆机研磨机磨粉机 | 1489462639 | 1391 | 1 |
2 | 88 | 老玩铜 关公关羽二爷武圣财神风水摆件镇宅招财进宝辟邪佛像 | 1489461722 | 1306 | 1 |
2.3.2 启动elasticsearch-jdbc插件
sh /usr/local/elasticsearch/jdbc/scripts/mysql_import_es.sh 前台执行 nohup sh /usr/local/elasticsearch/jdbc/scripts/mysql_import_es.sh > /usr/local/elasticsearch/jdbc/logs/jdbc.log 2>&1 & 后台启动
2.3.3 关闭elasticsearch-jdbc插件
ps -ef|grep ela #找到对应的程序pid kill -9 pid #kill掉该进程
当成功执行mysql_import_es.sh时,自动生成staticfile-tag.json和jdbc.log。”statefile” : “statefile-tag.json”这一条配置staticfile即staticfile-tag.json的生成。
连接的过程:启动mysql_import_es.sh,产生的staticfile中说明了数据库连接方式和字段匹配(mapping),ES 执行过程中通过staticfile的配置生成index。
为了保持数据库增量的自动更新,所查询的表中需要有时间戳字段,如例子中的”update_time”。“parameter” : [ “$metrics.lastexecutionstart” ]是指SQL语句最后一次执行的开始时间的时间戳。
schedule : 计划任务时间表,更新的时间差。
三、中文搜索测试
curl -XPOST http://192.168.1.100:9200/testindex/testtype/_search?pretty -d ' { "query" : { "match" : { "goods_name" : "磨豆机" }}, "size" : 10 }'
测试结果
{ "took" : 4, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 3946, "max_score" : 3.818761, "hits" : [ { "_index" : "testindex", "_type" : "testtype", "_id" : "1", "_score" : 3.4777398, "_source" : { "store_id" : 87, "goods_name" : "磨豆机 电动咖啡研磨机 家用 咖啡机磨咖啡豆机研磨机磨粉机8501", "cate_id" : 1391, "if_show" : 1, "add_time" : 1408071106, "is_hot" : 0, "shipping_id" : 201, "is_customizing" : 0, "start_stock" : 1, "price" : 300.0, "sort_order" : 81477, "state" : 1 } } ] } }
GOOD LUCK!
参考
搭建步骤 http://blog.csdn.net/stonesola/article/details/68489172
ik分词 https://github.com/medcl/elasticsearch-analysis-ik
jdbc连接 https://github.com/jprante/elasticsearch-jdbc
更多详情,请访问个人博客:https://www.wchonge.com