docker-compose搭建elasticsearch+kibana环境,以及php使用elasticsearch
一、elasticsearch的Dockerfile
增加中文搜索插件analysis-ik
FROM docker.elastic.co/elasticsearch/elasticsearch:7.2.0 ENV VERSION=7.2.0 # https://github.com/medcl/elasticsearch-analysis-ik/releases ADD https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v${VERSION}/elasticsearch-analysis-ik-$VERSION.zip /tmp/ RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install -b file:///tmp/elasticsearch-analysis-ik-$VERSION.zip RUN rm -rf /tmp/*
二、编写docker-compose.yml
version: '3' services: es01: image: "beng/es:7.2.0" build: . container_name: es01 restart: always volumes: - ./es01/data:/usr/share/elasticsearch/data:rw - ./es01/logs:/user/share/elasticsearch/logs:rw environment: - node.name=es01 - cluster.name=docker-cluster - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - discovery.seed_hosts=es02:9300,es03:9300 - cluster.initial_master_nodes=es01,es02,es03 ulimits: memlock: soft: -1 hard: -1 ports: - "9200:9200" - "9300:9300" networks: - esnet es02: image: "beng/es:7.2.0" build: . container_name: es02 restart: always volumes: - ./es02/data:/usr/share/elasticsearch/data:rw - ./es02/logs:/user/share/elasticsearch/logs:rw environment: - node.name=es02 - cluster.name=docker-cluster - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - discovery.seed_hosts=es01:9300,es03:9300 - cluster.initial_master_nodes=es01,es02,es03 ulimits: memlock: soft: -1 hard: -1 networks: - esnet es03: image: "beng/es:7.2.0" build: . container_name: es03 restart: always volumes: - ./es03/data:/usr/share/elasticsearch/data:rw - ./es03/logs:/user/share/elasticsearch/logs:rw environment: - node.name=es03 - cluster.name=docker-cluster - bootstrap.memory_lock=true - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - discovery.seed_hosts=es01:9300,es02:9300 - cluster.initial_master_nodes=es01,es02,es03 ulimits: memlock: soft: -1 hard: -1 networks: - esnet kibana: image: docker.elastic.co/kibana/kibana:7.2.0 container_name: kibana ports: - 5601:5601 volumes: - ./kibana/kibana.yml:/usr/share/kibana/config/kibana.yml:rw networks: - esnet networks: esnet:
三、编写kibana配置文件
看到网上很多人将elasticsearch.hosts这些参数直接配置在docker-compose文件里设置environment里面,
但是我在docker-compose文件里设置environment怎样都没有生效(原因没找到),于是直接自己写配置文件,并将配置文件磁盘映射到容器中
# # ** THIS IS AN AUTO-GENERATED FILE ** # # Default Kibana configuration for docker target server.name: kibana server.host: "0" elasticsearch.hosts: [ "http://es01:9200" ] xpack.monitoring.ui.container.elasticsearch.enabled: true i18n.locale: zh-CN
四、在php中使用elasticsearch
composer elasticsearch php库地址:https://packagist.org/packages/elasticsearch/elasticsearch
elasticsearch php的官方文档参考:https://www.elastic.co/guide/cn/elasticsearch/php/current/_quickstart.html
在根目录下引入库
composer require elasticsearch/elasticsearch
use Elasticsearch\ClientBuilder; //删除索引下的所有文档 private function deleteAllDoc() { $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); $params = [ 'index' => 'book', 'type' => '_doc', 'body' => [ 'query' => [ 'bool' => [ 'must_not' => ['term' => [ 'id' => -1000 ]], ] ] ] ]; $response = $client->deleteByQuery($params); echo "delete success\n"; print_r($response); } //删除某一个文档 private function deleteDoc($id = 0) { $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); $params = [ 'index' => 'book', 'type' => '_doc', 'id' => $id ]; $response = $client->delete($params); print_r($response); } //获取文档 private function getDoc($id = 0) { $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); $params = [ 'index' => 'book_index', 'type' => '_doc', 'id' => $id ]; try { $response = $client->get($params); print_r($response['_source']); } catch (Missing404Exception $e) { echo 'not exist!'; } } //添加文档 private function addDoc() { $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); $params = [ 'index' => 'my_index', 'type' => '_doc', 'id' => strval(2), 'body' => [ 'first_name' => '关 搜键隔字,以英逗索用号分,书本标文签用label字,不要段混淆', 'age' => 18 ] ]; $response = $client->index($params); print_r($response); print "\n"; } //删除索引 private function deleteIndex() { $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); $params = ['index' => 'book']; $response = $client->indices()->delete($params); print_r($response); } //创建索引 private function createIndex() { $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); $params = [ 'index' => 'book_index', 'body' => [ 'settings' => [ 'number_of_shards' => 2, 'number_of_replicas' => 1 ], 'mappings' => [ '_source' => [ 'enabled' => true ], 'properties' => [ 'id' => [ 'type' => 'integer', ], 'title' => [ 'type' => 'text', //使用ik中文分词 'analyzer' => 'ik_max_word' ], 'image' => [ 'type' => 'text' ], 'author' => [ 'type' => 'text', 'analyzer' => 'ik_max_word' ], 'words' => [ 'type' => 'integer' ], 'description' => [ 'type' => 'text', 'analyzer' => 'ik_max_word' ], 'is_vip' => [ 'type' => 'integer' ], 'bookstatus' => [ 'type' => 'text' ], 'online_status' => [ 'type' => 'integer' ], 'type_name' => [ 'type' => 'text' ], 'heat' => [ 'type' => 'integer' ], 'stars' => [ 'type' => 'float' ], ] ] ] ]; $response = $client->indices()->create($params); print_r($response); } //搜索书籍 public function searchBook($key, $vip = 0, $page = 1) { $size = 20; $words_size = 30; $match_num = 2; $offset = ($page - 1) * $size; $client = ClientBuilder::create() ->setHosts(config('api.elasticsearch_host')) ->build(); //插入到高亮搜索字前面的内容 $pre_tags = ""; //插入到高亮搜索字后面的内容 $post_tags = ""; $title_weight = 20; $author_weight = 20; $description_weight = 1; $params = [ 'index' => 'book_index', 'type' => '_doc', //分页 "from" => $offset, "size" => $size, 'body' => [ 'query' => [ 'bool' => [ //其他必须条件,书的vip 'must' => ['term' => [ 'is_vip' => intval($vip) ]], //其他必须条件,书的状态必须为已上架 'must' => ['term' => [ 'online_status' => 5 ]], //撞击分数规则 'should' => [ 'multi_match' => [ //搜索关键字 'query' => $key, //书的标题权重20,书的作者标题权重20,书简述权重为1 'fields' => ['title^'.$title_weight, 'author^'.$author_weight, 'description^'.$description_weight], "type" => "cross_fields", "operator" => "OR", //至少匹配度30% "minimum_should_match" => "30%" ] ] ] ], //关键字高亮 'highlight' => [ //匹配包含关键字的高亮次数,比如有30段文本包含关键字,如果只需要前面两次的,那$match_num=2 'number_of_fragments' => $match_num, //匹配包含关键字的高亮段落保留多少文字,比如一片文章中有30个片段包含关键字, //每个片段保留30个文字,则$words_size=30,多余的会忽略 'fragment_size' => $words_size, 'fields' => [ //高亮的字段,这里高亮书的标题和作者以及书简述 'title' => ['pre_tags' => $pre_tags, 'post_tags' => $post_tags,], 'author' => ['pre_tags' => $pre_tags, 'post_tags' => $post_tags,], 'description' => ['pre_tags' => $pre_tags, 'post_tags' => $post_tags,], ] ] ] ]; $results = $client->search($params); $hits = $results['hits']['hits']; if (empty($results['hits']['hits'])) { return []; } $books = []; //提取书信息 foreach ($hits as $key => $value) { $book = []; $book['book_id'] = $value['_source']['id']; if (!empty($value['highlight']['title'])) { $book['title'] = $value['highlight']['title'][0]; } else { $book['title'] = $value['_source']['title']; } if (!empty($value['highlight']['author'])) { $book['author'] = $value['highlight']['author'][0]; } else { $book['author'] = $value['_source']['author']; } if (!empty($value['highlight']['description'])) { $book['description'] = $value['highlight']['description'][0]; if (!empty($value['highlight']['description'][1])) { $book['description'] = $book['description']. '...' .$value['highlight']['description'][1]; } } else { $book['description'] = $value['_source']['description']; } $book['description'] = str_replace(array( "\r\n", "\n\n", "\r", " "), "", $book['description']); $book['bookstatus'] = $value['_source']['bookstatus']; $book['image'] = $value['_source']['image']; $book['words'] = $value['_source']['words']; $book['stars'] = $value['_source']['stars']; $book['heat'] = $value['_source']['heat']; $book['type_name'] = $value['_source']['type_name']; array_push($books, $book); } return $books; }