微服务实用篇5-分布式搜索elasticsearch篇1

今天的主要学习任务是分布式搜索,首先了解elasticsearch,然后学习索引库的操作、文档的操作、RestAPI等。elasticsearch是非常强大的开源搜索引擎,可以帮助我们从海量数据中快速定位到我们需要的内容。这一篇主要学习ES的基本使用,包括安装ES,安装kibana,安装分词器等,另外也学习了在java客户端实现索引库的增删改查和文档的增删改查。

目录

一、初识elasticsearch

1.1、了解ES

1.2、 倒排索引

1.3、ES与MySQL概念对比

1.4、安装ES

1.5、安装kibana

1.6、安装IK分词器 

1.7、IK分词器的扩展与停用

二、索引库操作

2.1、mapping映射属性

2.2、创建、查询、删除、修改索引库

2.3、文档的添加、查询、删除、修改

三、RestClient操作

3.1、RestClient操作索引库

3.2、RestClient操作文档


一、初识elasticsearch

1.1、了解ES

elasticsearch是非常强大的开源搜索引擎,可以帮助我们从海量数据中快速定位到我们需要的内容。elastic stack(ELK) 主要包含如下三部分,其中es是用于搜索和存储等,是该技术栈的核心,另外还包括数据抓取和数据可视化的技术栈。

微服务实用篇5-分布式搜索elasticsearch篇1_第1张图片

下面对elasticsearch做个小总结吧,es是开源的分布式搜索引擎,用来搜索、日志统计、分析等,ELK是以ES为核心的技术栈,包括数据可视化的Kibana和数据抓取的Logstash和Beats。另外Lucene是开源搜索引擎类库,提供搜索引擎核心的API。es底层是基于Lucene实现的。

微服务实用篇5-分布式搜索elasticsearch篇1_第2张图片

1.2、 倒排索引

我们先看一下正向索引,比如MySQL就是典型的采用正向索引,例如根据内容进行搜索,比对成功,则存储,比对失败,则丢弃。

微服务实用篇5-分布式搜索elasticsearch篇1_第3张图片

正向索引的搜索是一条一条的搜索,而倒排搜索是将数据划分成词条和文档 ,每次搜索前先分词,然后根据词条进行搜索,找到文档id,最后再根据文档id进行搜索,将搜索到的结果按照顺序存入结果集。在复杂的场景适合用倒排索引进行搜索,效率更高。

微服务实用篇5-分布式搜索elasticsearch篇1_第4张图片

1.3、ES与MySQL概念对比

我们看一下MySQL和es的概念对比,表对应索引,行对应文档,列对应字段,schema对应映射Mapping,SQL对应DSL。

微服务实用篇5-分布式搜索elasticsearch篇1_第5张图片

 对于数据安全要求较高的写相关操作,一般使用MySQL数据库,对于性能要求较高的读相关操作,一般使用Elasticsearch完成。MySQL和ES之间也可以实现数据同步。

微服务实用篇5-分布式搜索elasticsearch篇1_第6张图片

1.4、安装ES

下面看一下部署单点ES,我们需要先创建网络,因为我们还需要部署kibana容器,因此需要让es和kibana容器互联。这里先创建一个网络:当然需要先启动docker,再创建网络:

docker network create es-net

接下来就是加载es镜像了,一般来说,可以直接从服务器拉取,但是由于es镜像比较大,我们先下载到本地,然后通过xftp上传到虚拟机,然后使用load命令加载压缩包为镜像即可。

docker load -i es.tar

把kibana也上传到虚拟机,然后用load命令加载镜像,如下:

docker load -i kibana.tar

接下来就可以运行docker命令,部署单点es,如下:

命令解释:
● -e "cluster.name=es-docker-cluster" :设置集群名称
● -e "http.host=0.0.0.0" :监听的地址,可以外网访问
● -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" :内存大小
● -e "discovery.type=single-node" :非集群模式
● -v es-data:/usr/share/elasticsearch/data :挂载逻辑卷,绑定es的数据目录
● -v es-logs:/usr/share/elasticsearch/logs :挂载逻辑卷,绑定es的日志目录
● -v es-plugins:/usr/share/elasticsearch/plugins :挂载逻辑卷,绑定es的插件目录
● --privileged :授予逻辑卷访问权
● --network es-net :加入一个名为es-net的网络中
● -p 9200:9200 :端口映射配置

docker run -d \
--name es \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--network es-net \
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1

在浏览器输入ip地址+端口号检验es是否安装成功,如下所示出现如下json字符串则安装成功:

微服务实用篇5-分布式搜索elasticsearch篇1_第7张图片

1.5、安装kibana

kibana可以给我们提供一个elasticsearch的可视化界面,便于我们学习,我们首先运行docker,部署kibana,具体如下所示:

docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
--network=es-net \
-p 5601:5601 \
kibana:7.12.1

安装完成后可以在浏览器使用ip地址+端口号的方式打开可视化界面,如下:

微服务实用篇5-分布式搜索elasticsearch篇1_第8张图片

1.6、安装IK分词器 

有常见的两种方式安装IK分词器,分别在线安装和离线安装,在线安装的docker命令如下,不过该方法比较慢。

# 进入容器内部
docker exec -it elasticsearch /bin/bash
# 在线下载并安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip
#退出
exit
#重启容器
docker restart elasticsearch

另外一种安装IK分词器的方式是离线安装,具体如下,安装插件需要知道elasticsearch的plugins目录位置,而我们用了数据卷挂载,因此需要查看elasticsearch的数据卷目录,通过下面命令查看:

docker volume inspect es-plugins

plugins目录被挂载到了: /var/lib/docker/volumes/es-plugins/_data 这个目录中,我们将解压的ik分词器上传到这个目录中,然后重启容器即可。

docker restart es

最后测试IK分词的两种模式:在es的可视化界面使用Dev Tools进行测试即可,如下:

● ik_smart :最少切分
● ik_max_word :最细切分

微服务实用篇5-分布式搜索elasticsearch篇1_第9张图片

1.7、IK分词器的扩展与停用

ik分词器的扩展是很有必要的,因为词库是有限的,对于新的词汇,我们需要对分词器进行拓展,对于没有必要的分词,或者敏感词汇,也可以设置不进行分词,即停用,防止浪费内存。

1)首先打开ik分词器的config目录:
微服务实用篇5-分布式搜索elasticsearch篇1_第10张图片

2)在IKAnalyzer.cfg.xml配置文件扩展词典和停用词典,如下:




	IK Analyzer 扩展配置
	
	
	 
	
	
                ext.dic
	
	stopword.dic

3)在config文件夹内创建扩展和停用的文件,并设置相应的词语。

微服务实用篇5-分布式搜索elasticsearch篇1_第11张图片

微服务实用篇5-分布式搜索elasticsearch篇1_第12张图片

4)重启elasticsearch

docker restart es
docker restart kibana

5)测试 

微服务实用篇5-分布式搜索elasticsearch篇1_第13张图片

二、索引库操作

2.1、mapping映射属性

mapping常见的属性包括数据类型、是否索引、分词器、子字段等,常见的数据类型包括:文本或键值对字符串,数字,布尔类型,日期和对象类型等。

微服务实用篇5-分布式搜索elasticsearch篇1_第14张图片

2.2、创建、查询、删除、修改索引库

Elasticsearch通过Restful请求操作索引库和文档,请求内容通过DSL语句来表示,创建索引库和mapping的DSL如下:

微服务实用篇5-分布式搜索elasticsearch篇1_第15张图片

 下面在es的可视化界面的使用Dev Tools创建索引库,如下:


#创建索引库
PUT /wang
{
 
  "mappings": {
      "properties": {
        "info": {
              "type": "text",
              "analyzer": "ik_smart"
            },
        "email": {
          "type": "keyword"
          , "index": false
        },
        "name": {
          "type": "object",
          "properties": {
            "firstname": {
              "type": "keyword"
            },
             "lastname": {
              "type": "keyword"
            }
          }
        }
      }
  }
}

如下所示,表明创建索引成功。

微服务实用篇5-分布式搜索elasticsearch篇1_第16张图片

查询索引库用GET,删除索引库用DELETE,修改索引库用PUT,只能添加新字段,不能修改之前的字段。

#查询索引库
GET /wang

#删除索引
DELETE /wang

#修改索引,添加新字段
PUT /wang/_mapping
{
"properties":{
  "age":{
    "type":"long"
  }
}
}

2.3、文档的添加、查询、删除、修改

创建文档使用POST,查询文档用GET、删除文档用DELETE、修改文档主要有两种,一种是全量修改,另一种是增量修改。

微服务实用篇5-分布式搜索elasticsearch篇1_第17张图片


#查询文档
GET /wang/_doc/1

#删除文档
DELETE /wang/_doc/1

#全量修改,修改文档
PUT /wang/_doc/1
{
  "info":"Java学习之路,慢慢来",
  "email":"[email protected]",
  "name":{
    "firstname":"忠",
    "lastname":"黄"
  }
}

#局部修改文档
POST /wang/_update/1
{
  "doc":{
    "email":"[email protected]"
  }
  
}

三、RestClient操作

3.1、RestClient操作索引库

我们要通过Java的客户端操作实现索引库的增删改查相关操作,首先需要导入demo,然后定于mapping映射,通过RestClient完成索引库的相关操作。

微服务实用篇5-分布式搜索elasticsearch篇1_第18张图片

初始化Java客户端,需要先引入依赖,并使用相应的IP地址何端口号进行初始化。

微服务实用篇5-分布式搜索elasticsearch篇1_第19张图片

 

创建库索引,如下主要分为三步,创建request对象,准备请求发送,最后是发送请求。

import org.apache.http.HttpHost;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import static cn.itcast.hotel.constants.HotelConstants.MAPPING;

public class HotelIndexTest {

    private RestHighLevelClient client ;

    @Test
    void testInits(){
        System.out.println(client);
    }

    @Test
    void TestInit() throws IOException {
        //1.创建request对象
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("hotel") ;
        //2.准备请求的参数
        createIndexRequest.source(MAPPING, XContentType.JSON) ;
        //3.发送请求
        client.indices().create(createIndexRequest, RequestOptions.DEFAULT) ;
    }


    @BeforeEach
    void setUp(){
        this.client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.132.128:9200"))) ;
    }

    @AfterEach
    void tearDown() throws IOException {
        this.client.close() ;
    }
}

因为是通过DSL语句创建索引库,所以这里定义了一个MAPPING常量,通过静态导包的方式加入,如下:

public class HotelConstants {
    public static final String MAPPING = "{\n" +
            "\"mappings\": {\n" +
            "\n" +
            "\"properties\": {\n" +
            "\n" +
            "\"id\":{\n" +
            "\n" +
            "\"type\": \"keyword\"\n" +
            "},\n" +
            "\"name\":{\n" +
            "\n" +
            "\"type\": \"text\",\n" +
            "\"analyzer\": \"ik_max_word\",\n" +
            "\"copy_to\": \"all\"\n" +
            "},\n" +
            "\"address\":{\n" +
            "\n" +
            "\"type\": \"keyword\",\n" +
            "\"index\": false\n" +
            "},\n" +
            "\"price\":{\n" +
            "\n" +
            "\"type\": \"integer\"\n" +
            "},\n" +
            "\"score\":{\n" +
            "\n" +
            "\"type\": \"integer\"\n" +
            "},\n" +
            "\"brand\":{\n" +
            "\n" +
            "\"type\":\"keyword\",\n" +
            "\"copy_to\": \"all\"\n" +
            "},\n" +
            "\"city\":{\n" +
            "\n" +
            "\"type\": \"keyword\"\n" +
            "},\n" +
            "\"starName\":{\n" +
            "\n" +
            "\"type\": \"keyword\"\n" +
            "},\n" +
            "\"business\":{\n" +
            "\n" +
            "\"type\": \"keyword\",\n" +
            "\"copy_to\": \"all\"\n" +
            "},\n" +
            "\"location\":{\n" +
            "\n" +
            "\"type\": \"geo_point\"\n" +
            "},\n" +
            "\"pic\":{\n" +
            "\n" +
            "\"type\": \"keyword\",\n" +
            "\"index\": false\n" +
            "},\n" +
            "\"all\":{\n" +
            "\n" +
            "\"type\": \"text\",\n" +
            "\"analyzer\": \"ik_max_word\"\n" +
            "}\n" +
            "}\n" +
            "}\n" +
            "}" ;
}

删除索引库何判断索引库是否存在的代码如下:

    //判断索引库是否存在
    @Test
    void TestExists() throws IOException {
        //1.创建request对象
        GetIndexRequest getIndexRequest = new GetIndexRequest("hotel") ;
        //2.发送请求
        boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT) ;
        //3.输出
        System.out.println(exists ? "索引库存在" : "索引库不存在");
    }


    //删除索引库
    @Test
    void TestDelete() throws IOException {
        //1.创建request对象
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("hotel") ;
        //2.发送请求
        client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT) ;
    }

3.2、RestClient操作文档

我们来看一下使用RestClient对文档进行增删改查的相关操作,具体如下:

首先需要初始化Java客户端,然后新增酒店数据到索引库,然后从索引库查询、删除、修改数据。

微服务实用篇5-分布式搜索elasticsearch篇1_第20张图片

 插入文档的代码如下,首先需要从数据库查询文档,这里面之前报了一个空指针异常,在测试类上加了@SpringBootTest注解后解决了,首先从数据库中查询,然后转换为文档类型,最后根据请求和Json对象发送新增文档请求即可。

    @Test //文档新增
    void addDocument() throws IOException {
        //根据id查询酒店数据
        Hotel hotel = iHotelService.getById(38665L) ;
        //转换为文档类型
        HotelDoc hotelDoc = new HotelDoc(hotel) ;

        //1.创建request对象
        IndexRequest indexRequest = new IndexRequest("hotel").id(hotel.getId().toString()) ;
        //2.准备Json对象
        indexRequest.source(JSON.toJSONString(hotelDoc), XContentType.JSON) ;
        //3.发送请求
        client.index(indexRequest, RequestOptions.DEFAULT) ;
    }

可在es的可视化界面中使用指令查询索引库中添加的文档,如下:

微服务实用篇5-分布式搜索elasticsearch篇1_第21张图片

根据id查询酒店数据,具体如下:

    @Test //文档查询
    void getDocumentById() throws IOException {

        //1.创建request对象
        GetRequest getRequest = new GetRequest("hotel", "38665") ;
        //2.发送请求,得到响应
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT) ;
        //3.解析响应的结果
        String json = getResponse.getSourceAsString() ;

        HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class) ;
        System.out.println(hotelDoc);
    }

微服务实用篇5-分布式搜索elasticsearch篇1_第22张图片 根据id进行文档的修改,也就是更新,就是全量更新和局部更新。

    @Test //文档更新
    void updateDocumentById() throws IOException {

        //1.创建request对象
        UpdateRequest updateRequest = new UpdateRequest("hotel", "38665") ;
        //2.准备请求参数
        updateRequest.doc("price","999","starName","3钻") ;
        //3.发送请求
        client.update(updateRequest,RequestOptions.DEFAULT) ;

    }

 接下来,我们进行删除文档,如下:

    @Test //文档删除
    void deleteDocumentById() throws IOException {

        //1.创建request对象
        DeleteRequest deleteRequest = new DeleteRequest("hotel", "38665") ;
        //2.发送请求
        client.delete(deleteRequest,RequestOptions.DEFAULT) ;

    }

最后对文档操作做个总结:首先需要初始化客户端,然后创建请求对象,准备参数,发送请求,最后解析请求得到的结果即可。

微服务实用篇5-分布式搜索elasticsearch篇1_第23张图片

 最后我们在看一个批量导入数据到ES中,就是将文档数据批量导入到索引库中,具体如下:

微服务实用篇5-分布式搜索elasticsearch篇1_第24张图片

 下面是文档批量导入的代码,如下:

    @Test //文档批量处理
    void bulkDocumentById() throws IOException {

        //批量出巡酒店数据
        List list = iHotelService.list() ;
        //1.创建request对象
        BulkRequest bulkRequest = new BulkRequest() ;

        //转换为文档类型
        for(Hotel hotel : list){
            HotelDoc hotelDoc = new HotelDoc(hotel) ;
            //创建文档的request对象
            bulkRequest.add(new IndexRequest("hotel")
                    .id(hotel.getId().toString())
                    .source(JSON.toJSONString(hotelDoc),XContentType.JSON)) ;
        }

       //2.发送请求
        client.bulk(bulkRequest,RequestOptions.DEFAULT) ;

    }

你可能感兴趣的:(elasticsearch,微服务,分布式,java,intellij-idea)