ElasticSearch学习

ElasticSearch介绍

引言

  1. 在海量数据中执行搜索功能, Mysql对于大数据的搜索,效率太低
  2. 如果关键字不准确, 一样可以搜索到想要的数据

es介绍

es是使用java语言并且基于Lucene编写的搜索引擎框架, 提供了分布式的全文检索功能, 可以近乎实时的存储, 检索数据, 提供了统一的基于RESTful风格的web接口, 官方客户端对多种语言提供了相应的API

Lucene: Lucene本身就是一个搜索引擎的底层, 本质是一个jar包,里面包含了封装好的各种建立倒排索引,以及进行搜索的代码,包括各种算法。

全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,根据关键字去分词库中进行检索, 找到匹配内容

结构化检索:我想搜索商品分类为日化用品的商品都有哪些,select * from products where category_id=‘日化用品’

es和solr

  1. Solr在查询死数据时, 速度相对于es会更快. 但是如果数据是实时改变的, Solr的查询速度会降低很多, ES的查询效率基本没有变化

  2. Solr搭建基于需要依赖Zookeeper来帮助管理. ES本身就支持集群的搭建, 不需要第三方介入

  3. Solr针对国内的文档并不多, 在ES出现后, 火爆程度直线上升, 文档非常健全

  4. ES对云计算和大数据支持特别好

倒排索引

将存放的数据, 按照一定的方式进行分词, 并且将分词的内容存放到一个单独的分词库中

当用户去查询时, 会将用户的查询关键词进行分词

然后去分词库中匹配内容, 最终得到数据的id标识

根据id标识去存放数据的位置拉取到指定的数据

image-20210301165903923

ElasticSearch安装

安装ES&Kibana

安装ES

version: "3.1"
services:
  elasticsearch:
    image: daocloud.io/library/elasticsearch:6.5.4
    restart: always
    container_name: elasticsearch
    environment:  # 分配的内存,必须指定,因为es默认指定2g,直接内存溢出了,必须改
      - "ES_JAVA_OPTS=-Xms128m -Xmx256m"
      - "discovery.type=single-node"
      - "COMPOSE_PROJECT_NAME=elasticsearch-server"
    ports:
      - 9200:9200
  kibana:
    image: daocloud.io/library/kibana:6.5.4
    restart: always
    container_name: kibana
    ports:
      - 5601:5601
    environment:
      - elasticsearch_url:http://115.159.222.145:9200
    depends_on:
      - elasticsearch
es文件目录
bin 启动文件
config 配置文件
	-log4j2 日志配置
	-jvm.options java虚拟机配置, 配置运行所需内存, 内存不够时配置小一点
	-elasticsearch.yml elasticsearch配置文件, 端口9200
lib 相关jar包
logs 日志
module 功能模块
plugins 插件
elasticsearch启动不起来

elasticsearch exited with code 78

解决:

切换到root用户

执行命令:

sysctl -w vm.max_map_count=262144

查看结果:

sysctl -a|grep vm.max_map_count

显示:

vm.max_map_count = 262144

上述方法修改之后,如果重启虚拟机将失效,所以:

解决办法:

在 /etc/sysctl.conf文件最后添加一行

vm.max_map_count=262144

如果还有问题,注意服务器的内存状态, 可能是内存不够, 需要清理出一些内存.

启动成功后测试

浏览器访问es

http://host:9200
image-20210301180515025

安装Kibana

kibana是一个针对ElasticSearch的开源分析及可视化平台, 用来搜索, 查看交互存储在es索引中的数据.可以通过各种图标进行高级数据分析及展示.

操作简单方便, 数据展示直观

在访问kibana

http://host:5601

image-20210301180444514

安装可视化ES插件head

  1. 下载地址:http://mobz.github.io/elasticsearch-head

  2. 启动

    npm install
    npm run start
    
  3. 跨域问题解决

    # 修改es配置文件elasticsearch.yml
    http.cors.enabled: true
    http.cors.allow-origin: "*"
    
  4. 重启es服务器, 再次连接

安装ik分词器

ik分词器下载地址

https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip

查看es容器

docker ps | grep elastic

进入es容器内部, 执行bin/目录下elasticsearch-plugin安装ik分词器

./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.4/elasticsearch-analysis-ik-6.5.4.zip

如果github网络不好,可以找其他版本使用国内路径

使用接口测试分词效果

注意:

需要重启es加载安装的分词器

docker restart es容器名/id

等待重启后测试分词

POST _analyze
{
  "analyzer": "ik_max_word",
  "text": "尚硅谷教育"
}

需要指定分词器类型 analyzer

返回值

{
  "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" : 3,
      "end_offset" : 5,
      "type" : "CN_WORD",
      "position" : 2
    }
  ]
}

image-20210301180750084

ElasticSearch核心

ES组件

近实时

分为两个意思

  1. 从写入数据到数据可以被搜索到有一个小延迟(大概1秒);
  2. 基于es执行搜索和分析可以达到秒级。
Cluster(集群)

集群包含多个节点,每个节点属于哪个集群是通过一个配置(集群名称,默认是elasticsearch)来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常

node(节点)

集群中的一个节点,节点也有一个名称(默认是随机分配的),节点名称很重要(在执行运维管理操作的时候),默认节点会去加入一个名称为“elasticsearch”的集群,如果直接启动一堆节点,那么它们会自动组成一个elasticsearch集群,当然一个节点也可以组成一个elasticsearch集群。

ElasticSearch存储结构

image-20210301184034340

image-20210301184107129

Index(索引-数据库)

索引包含一堆有相似结构的文档数据,ES服务中,可以建立多个索引

如可以有一个客户索引,商品分类索引,订单索引,索引有一个名称。

  1. 每一个索引默认分为5片存储
  2. 每个分片会存在至少一个备份
  3. 备份分片默认不会帮助检索,当检索压力特别大时, 备份才会帮助检索
  4. 备份分片需要放在不同的服务器中

Type(类型-表)

每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field

注意:

  • ES5.x版本,一个Index下可以创建多个Type
  • ES5.x版本,一个Index下可以创建一个Type
  • ES5.x版本,一个Index没有Type

Document(文档-行)

文档是es中的最小数据单元,一个类型下可以有多个document, 一个document可以是一条或多条客户数据

Field(字段-列)

Field是Elasticsearch的最小单位。一个document里面有多个field,每个field就是一个数据字段。

操作ES的RESTful语法

GET请求:

  • http://ip:port/index: 查询索引信息
  • http://ip:port/index/type/doc_id: 查询指定的文档信息

POST请求:

  • http://ip:port/index/type/_search: 查询文档, 可以在请求体中添加json字符串代表查询条件
  • http://ip:port/index/type/doc_id/_update: 修改文档, 可以在请求体中添加json字符串代表修改的具体内容

PUT请求:

  • http://ip:port/index: 创建一个索引, 需要在请求体中指定索引的具体信息
  • http://ip:port/index/type/_mapping: 代表创建索引时, 指定索引文档存储的属性信息

DELETE请求:

  • http://ip:port/index: 删除索引
  • http://ip:port/index/type/doc_id: 删除指定文档

索引的操作

创建一个索引

PUT /person
{
   
  "settings": {
   
    "number_of_shards": 5,
    "number_of_replicas": 1
  }
}

查看索引信息

  1. kibana图形界面查询

image-20210301185729297

  1. 接口查询

    # 查看索引信息
    GET /person
    

    返回

    {
         
      "person" : {
         
        "aliases" : {
          },
        "mappings" : {
          },
        "settings" : {
         
          "index" : {
         
            "creation_date" : "1614596113957",
            "number_of_shards" : "5",
            "number_of_replicas" : "1",
            "uuid" : "bC8PJsegQ16t5EAtNWh_vg",
            "version" : {
         
              "created" : "6050499"
            },
            "provided_name" : "person"
          }
        }
      }
    }
    

删除索引

  1. 图形管理界面

    image-20210301190106655

  2. 接口删除

    # 删除索引
    DELETE /person
    

    返回

    {
      "acknowledged" : true
    }
    

ES中Field类型

String:

  • text: 用于全文检索, 将当前Field进行分词
  • keyworld: 当前Field不会被分词

数值类型:

  • long
  • integer
  • byte
  • double
  • float

时间类型:

  • date类型: 针对时间类型指定具体的格式

布尔类型:

  • boolean类型, 表达true和false

二进制类型:

  • binary类型暂时支持Base64 encoding string

范围类型:

  • long_range: 赋值是,只需存储一个范围即可, 指定gt, lt, gte, lte
  • float_range:
  • integer_range:
  • date_range:
  • ip_range:

经纬度类型:

  • geo_point: 用来存储经纬度的

ip类型:

  • ip: 可以存储ipv4或者ipv6

其他

创建索引并指定数据结构

# 创建索引, 指定数据类型
PUT /book
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  },
  "mappings": {
    "novel": {
      "properties": {
        "name": {
          "type": "text",
          "analyzer": "ik_max_word",
          "index": true,
          "store": false 
        },
        "author": {
          "type": "keyword"
        },
        "count": {
          "type": "long"
        },
        "onSale": {
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd|epoch_millis"
        },
        "desc": {
          "type": "text",
          "analyzer": "ik_max_word"
        }
      }
    }
  }
}

解释:

  • number_of_shards: 分片
  • number_of_replicas: 备份
  • mappings: 指定数据结构
  • novel: 指定的类型名
  • properties: 文档中字段的定义
  • name: 指定一个字段名为name
  • type: 指定该字段的类型
  • analyzer: 指定使用的分词器
  • index: true指定当前的field可以被作为查询条件
  • store: 是否需要额外存储
  • format: 指定时间存储的格式

文档的操作

文档在ES服务器中唯一的标识, _index, _type, _id三个内容为组合, 锁定一个文档, 操作时添加还是修改

新建文档

自动生成id

# 添加文档
POST /book/novel
{
  "name": "斗罗",
  "author": "西红柿",
  "count": 10000,
  "onSale": "2000-01-01",
  "desc": "斗罗大陆修仙小说"
}

手动指定id

# 手动指定id
PUT /book/novel/1
{
  "name": "红楼梦",
  "author": "曹雪芹",
  "count": 10000,
  "onSale": "1758-01-01",
  "desc": "红楼梦小说"
}
修改文档

覆盖式修改

# 手动指定id
PUT /book/novel/1
{
  "name": "红楼梦",
  "author": "曹雪芹",
  "count": 20000,
  "onSale": "1758-01-01",
  "desc": "红楼梦小说"
}

doc修改方式

# 修改文档,基于doc方式
POST /book/novel/1/_update
{
  "doc": {
    "count": 123455
    # 指定修改的field和对应的值
  }
}
删除文档
# 根据id删除文档
DELETE /book/novel/Ile37XcBdlEqQ4RmWKpJ

Java操作ElasticSearch

java连接ES

  1. 创建maven工程

  2. 导入依赖

    <dependencies>
        <!-- 1.elasticsearch -->
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.5.4</version>
        </dependency>
        <!-- 2.elasticsearch API -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.5.4</version>
        </dependency>
        <!-- 3. junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!-- 4. lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
        <!-- 5. jackson -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.2</version>
        </dependency>
    </dependencies>
    
  3. 创建es连接

    package com.example.utils;
    
    import org.apache.http.HttpHost;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestClientBuilder;
    import org.elasticsearch.client.RestHighLevelClient;
    
    /**
     * @author : ryxiong728
     * @email : ryxiong728@126.com
     * @date : 3/1/21
     * @Description:
     */
    public class ESClient {
         
        public static RestHighLevelClient getClient() {
         
            // 1.创建HttpHost对象
            HttpHost httpHost = new HttpHost("115.159.222.145", 9200);
    
            // 2. 创建RestClientBuilder
            RestClientBuilder clientBuilder = RestClient.builder(httpHost);
    
            // 3. 创建RestHighLevelClient
            RestHighLevelClient client = new RestHighLevelClient(clientBuilder);
            // 返回client对象
            return client;
        }
    }
    

java操作索引

创建索引

package com.example.test;

import com.example.utils.ESClient;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.junit.Test;

import java.io.IOException;

/**
 * @author : ryxiong728
 * @email : ryxiong728@126.com
 * @date : 3/1/21
 * @Description:
 */
public class Demo02 {
   
    RestHighLevelClient client = ESClient.getClient();
    String index = "person";
    String type = "info";
    /*
    "mappings": {
        "novel": {
          "properties": {
            "name": {
              "type": "text",
              "analyzer": "ik_max_word",
              "index": true,
              "store": false
            },
            "author": {
              "type": "keyword"
            },
            "count": {
              "type": "long"
            },
            "onSale": {
              "type": "date",
              "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
            },
            "desc": {
              "type": "text",
              "analyzer": "ik_max_word"
            }
          }
        }
      }
     */
    @Test
    public void createIndex() throws IOException {
   
        // 1. 准备索引的settings
        Settings.Builder settings = Settings.builder();
        settings.put("number_of_shards", 3);
        settings.put("number_of_replicas", 1);

        // 2. 准备关于索引的结构mappings
        XContentBuilder mappings = JsonXContent.contentBuilder()
                .startObject()
                    .startObject("properties")
                        .startObject("name")
                            .field("type", "text")
                        .endObject()
                        .startObject("age")
                            .field("type", "integer")
                        .endObject()
                        .startObject("birthday")
                            .field("type", "date")
                            .field("format", "yyyy-MM-dd")
                        .endObject()
                    .endObject()
                .endObject();

        // 3. 将settings和mappings封装到Request对象中
        CreateIndexRequest request = new CreateIndexRequest(index);
        request.settings(settings);
        request.mapping(type, mappings);

        // 4. 通过client连接ES并创建索引
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);

        // 5. 输出
        System.out.println(response.toString());

    }
}

检查索引是否存在

@Test
public void isExists() throws IOException {
   
    // 1. 准备request对象
    GetIndexRequest request = new GetIndexRequest();
    request.indices(index);

    // 2. 通过client去操作
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);

    // 3. 打印
    System.out.println(exists);
}

删除索引

@Test
public void deleteIndex() throws IOException {
   
    // 1. 准备request对象
    DeleteIndexRequest delete = new DeleteIndexRequest();
    delete.indices(index);

    // 2. 通过client操作
    AcknowledgedResponse resp = client.indices().delete(delete, RequestOptions.DEFAULT);

    // 3. 获取返回结果
    System.out.println(resp.isAcknowledged());
}

java操作文档

添加文档

person实例

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
   
    @JsonIgnore  // 注解: 序列化是忽略id字段
    private Integer id;
    private String name;
    private Integer age;
    @JsonFormat(pattern = "yyyy-MM-dd")  // 序列化是将date格式化为 yyyy-MM-dd类型
    private Date birthday;

}

创建案例

package com.example.test;

import com.example.entity.Person;
import com.example.utils.ESClient;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.junit.Test;

import java.io.IOException;
import java.util.Date;

/**
 * @author : ryxiong728
 * @email : ryxiong728@126.com
 * @date : 3/1/21
 * @Description:
 */
public class Demo03 {
   
    ObjectMapper mapper = new ObjectMapper();
    RestHighLevelClient client = ESClient.getClient();
    String index = "person";
    String type = "info";

    @Test
    public void createDocument() throws IOException {
   
        // 1. 准备一个json数据
        Person person = new Person(1, "张三", 23, new Date());
        String json = mapper.writeValueAsString(person);
        System.out.println(json);

        // 2. 准备一个request对象
        IndexRequest indexRequest = new IndexRequest(index, type, person.getId().toString());
        indexRequest.source(json, XContentType.JSON);

        // 3. 通过client对象添加文档
        IndexResponse resp = client.index(indexRequest, RequestOptions.DEFAULT);

        // 4. 打印结果
        System.out.println(resp.getResult().toString());
    }
}


修改文档

@Test
public void updateDocument() throws IOException {
   
    // 1. 创建一个map, 指定修改的内容
    Map<String, Object> doc = new HashMap<String, Object>();
    doc.put("name", "李四");
    String docId = "1";

    // 2. 创建request对象, 封装数据
    UpdateRequest updateRequest = new UpdateRequest(index, type, docId);
    updateRequest.doc(doc);

    // 3. 通过client对象执行
    UpdateResponse response = client.update(updateRequest, RequestOptions.DEFAULT);

    // 4. 输出返回结果
    System.out.println(response.getResult().toString());

}

删除文档

@Test
public void deleteDocument() throws IOException {
   
    // 1. 封装request对象
    DeleteRequest deleteRequest = new DeleteRequest(index, type, "1");

    // 2. 通过client执行
    DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);

    // 3. 输出结果
    System.out.println(response.getResult().toString());

}

java批量操作文档

批量添加文档

@Test
public void bulkCreateDocument() throws IOException {
   
    // 1. 准备多个json数据
    Person p1 = new Person(1, "张三", 23, new Date());
    Person p2 = new Person(2, "李四", 24, new Date());
    Person p3 = new Person(3, "王五", 25, new Date());

    String json1 = mapper.writeValueAsString(p1);
    String json2 = mapper.writeValueAsString(p2);
    String json3 = mapper.writeValueAsString(p3);

    // 2. 创建Request, 将准备好的数据封装
    BulkRequest bulkRequest = new BulkRequest();
    bulkRequest.add(new IndexRequest(index, type, p1.getId().toString()).source(json1, XContentType.JSON));
    bulkRequest.add(new IndexRequest(index, type, p2.getId().toString()).source(json2, XContentType.JSON));
    bulkRequest.add(new IndexRequest(index, type, p3.getId().toString()).source(json3
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于学习Elasticsearch,我可以给你一些指导。Elasticsearch是一个开源的分布式搜索和分析引擎,主要用于快速、实时地存储、搜索和分析大量数据。下面是一些学习Elasticsearch的步骤: 1. 了解基本概念:开始学习Elasticsearch之前,你需要了解一些基本的概念,比如索引(index)、类型(type)、文档(document)、字段(field)等。这将帮助你更好地理解Elasticsearch的工作原理。 2. 安装和配置:根据你的操作系统,你可以从Elasticsearch官方网站下载并安装合适的版本。安装完成后,你需要进行适当的配置,如设置集群名称、分配内存等。 3. 学习REST API:Elasticsearch提供了丰富的REST API,用于与其进行交互。了解如何使用这些API来索引、搜索和删除数据是学习Elasticsearch的重要一步。 4. 索引和搜索数据:学习如何创建索引、添加文档以及执行搜索操作是使用Elasticsearch的关键。掌握查询语法、过滤器、聚合操作等功能可以帮助你更有效地使用Elasticsearch。 5. 数据建模和分析:学习如何设计合适的数据模型和映射,以及如何使用Elasticsearch进行数据分析和可视化是提高你的技能的重要一步。 6. 扩展和优化:学习如何在生产环境中扩展和优化Elasticsearch集群是非常重要的。了解如何分片、复制、调优性能等将帮助你更好地管理和维护你的数据。 7. 学习资源:除了官方文档,还有很多优秀的学习资源可供参考,如书籍、教程和在线课程等。利用这些资源可以更系统地学习和掌握Elasticsearch。 希望这些步骤能对你学习Elasticsearch有所帮助!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值