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 }
View Code

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
View Code

注:执行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

posted @ 2018-01-22 16:53  曾想仗剑走天涯  阅读(1019)  评论(0编辑  收藏  举报