24、ElasticSearch

安装ElasticSearch

  • 安装1.8及以上的jdk
  • https://www.elastic.co/cn/downloads/elasticsearch 下载对应版本
  • 上传到云服务器 /usr/local/software/ 目录下
  • tar -zxvf elasticsearch-7.12.1-linux-x86_64.tar.gz解压
  • cd /usr/local/software/elasticsearch-7.12.1/bin
  • 执行./elasticsearch报错
    java.lang.RuntimeException: can not run elasticsearch as root
  • 新建es用户
  • cd /usr/local/software
  • groupadd esgroup
  • useradd esuser -g esgroup -p 123456
  • chown -R esuser:esgroup elasticsearch-7.12.1/
  • su - esuser
  • ./elasticsearch 前台启动
  • ./elasticsearch -d 后台启动 需要等一段时间
  • 配置跨域访问 /usr/local/software/elasticsearch-7.12.1/config/elasticsearch.yml 最后添加下面两行
http.cors.enabled: true
http.cors.allow-origin: "*"
  • curl 127.0.0.1:9200 成功会有相应信息

  • 如果出现 max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]错误 编辑 /etc/sysctl.conf,追加以下内容:vm.max_map_count=655360保存后,执行:sysctl -p

  • 出现 max file descriptors [65535] for elasticsearch process is too low, increase to at least [65536] 切换到root用户编辑 /etc/security/limits.conf,追加以下内容

    soft nofile 65536
    hard nofile 65536
    
  • 默认只允许本机访问 配合Nginx 实现外网访问

   upstream es_pool{
        server 127.0.0.1:9200;
    }

    upstream es_header_pool{
        server 127.0.0.1:9100;
    }

    server {
        listen       80;
        server_name  localhost;

        location /es/ {
            proxy_pass http://es_pool/;
            proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /es_header/ {
            proxy_pass http://es_header_pool/;
            proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
     }
  • 允许内网访问的 elasticsearch.yml 配置文件
cluster.name: my-application
node.name: node-1
network.host: 0.0.0.0
http.port: 9200
discovery.seed_hosts: ["127.0.0.1", "[::1]"]
cluster.initial_master_nodes: ["node-1"]

http.cors.allow-origin: "*"
http.cors.enabled: true
http.cors.allow-headers : X-Requested-With,X-Auth-Token,Content-Type,Content-Length,Authorization
http.cors.allow-credentials: true

安装ElasticSearch-Head

  • 通过https://nodejs.org/en/download/ 下载nodejs版本

  • 上传到/usr/local/software下面

  • tar -xvf node-v14.17.0-linux-x64.tar.xz 解压

  • export PATH=$PATH:/usr/local/software/node-v14.17.0-linux-x64/bin

  • ln -s /usr/local/software/node-v14.17.0-linux-x64/bin/npm /usr/local/bin/
    ln -s /usr/local/software/node-v14.17.0-linux-x64/bin/node /usr/local/bin/

  • 执行node -v 打印版本 成功

  • 通过 https://github.com/mobz/elasticsearch-head 下载最新版本

  • yum install -y unzip zip 安装unzip解压

  • 上传到/usr/local/software/ unzip elasticsearch-head-master.zip

  • npm install -g grunt-cli 安装依赖

  • yum install bzip2 //可能会报解压错误 没有忽略即可

  • npm install cnpm -g --registry=https://registry.npm.taobao.org 使用npm因为网络原因总是报错

  • cd elasticsearch-head-master/ 执行 cnpm install

  • 修改Gruntfile.js

connect: {
    server: {
        options: {
            hostname: '*', # 添加这一行
            port: 9100,
            base: '.',
            keepalive: true
        }
    }
}
  • 修改_site下面的app.js 4388行左右将localhost替换成ElasticSearch的服务器地址
this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://192.168.0.199:9200";
  • npm run start 启动
  • nohup npm run start & 后台启动

安装 Kibana

server.host: "192.168.0.199"
elasticsearch.hosts: ["http://192.168.0.199:9200"]
i18n.locale: "zh-CN"
  • 执行bin目录下的kibana ./kibana --allow-root
  • 访问 http://192.168.0.199:5601/

ElasticSearch 术语

  • 索引index —— 拥有相似文档的集合
  • 类型type —— 一个索引中可以定义多个类型
  • 字段field —— 相当于数据库表中的字段
  • 映射mapping —— 处理数据方式和规格方面做一些限制
  • 文档document —— 一个文档是一个可被索引的基础单元
  • 分片 —— 由于单台机器无法存储大量数据,ES 可以将一个索引中的数据切分为多个分片(Shard),分布在多台服务器上存储。
  • 复制 —— 备份

操作

{
    "mappings": {
        "properties": {
            "id": {
                "type": "long",
                "store": true
            },
            "title": {
                "type": "text",
                "store": true,
                "analyzer": "standard"
            },
            "content": {
                "type": "text",
                "store": true,
                "analyzer": "standard"
            }
        }
    }
}
  • 查看索引对应的映射 类型默认都是_doc
{
  "mappings": {
    "_doc": {
      "properties": {
        "content": {
          "type": "text",
          "store": true,
          "analyzer": "standard"
        },
        "id": {
          "type": "long",
          "store": true
        },
        "title": {
          "type": "text",
          "store": true,
          "analyzer": "standard"
        }
      }
    }
  }
}
{
  "mappings": {
    "db1": {
      "properties": {
        "content": {
          "type": "text",
          "store": true,
          "analyzer": "standard"
        },
        "id": {
          "type": "long",
          "store": true
        },
        "title": {
          "type": "text",
          "store": true,
          "analyzer": "standard"
        }
      }
    }
  }
}
  • DELETE请求删除索引库 http://192.168.0.199/es/test1
  • 添加文档(一条数据就是一个文档)http://192.168.0.199/es/test/db1/1 在db1类型下设置id为1的数据 下面是请求体 保持和映射一致就行 如果db1后面不加/1 会自动生成一个随机字符串id 操作时一般保持id字段和请求体里面的id字段保持一致
{
    "id":1,
    "title":"文档标题",
    "content":"文档内容"
}
  • id设置相同数据会被覆盖 用来实现修改文档

  • DELETE方法删除文档 http://192.168.0.199/es/test/db1/1

  • 查询

        {
            "query_string":{
                "term":{
                    "default_field":"title",
                    "query":"文档"                
                }
            }
        }
    
    {
      "analyzer" : "standard",
      "text": ["文档标题2"]
    }
    
    • 关键词查询 like query_string 先对查询内容分词
     {
            "query":{
                "query_string":{ 
                    "query":"title:(\"题2\")",
                    "default_operator": "and"
                }
            }
        }
    

    or

    {
        "query": {
            "match_phrase": {
                "title": "题2"
            }
        }
    }
    

安装中文分词器IK

ElasticSearch内置分词器

  1. standard分词器:(默认分词器)它会将词汇单元转换成小写形式,并除去停用词(a、an、the等)和标点符号,支持中文采用的方法为单字切分。
  2. simple分词器:首先会通过非字母字符来分割文本信息,然后将词汇单元统一成小写形式,该分词器会去掉数据类型的字符。
  3. Whitespace分词器:仅仅是去掉空格,对字符没有lowcase化,不支持中文;并且不对生成的词汇单元进行其他的标准化处理。
  4. language分词器:特定语言的分词器,不支持中文

中文分词器的安装

  • https://github.com/medcl/elasticsearch-analysis-ik/releases 下载最新版本的zip包
  • cd /usr/local/software/elasticsearch-7.12.1/plugins/
  • mkdir ik
  • 把文件移动到ik目录下
  • cd ik/
  • unzip elasticsearch-analysis-ik-7.12.1.zip
  • 切换用户重启 elasticsearch
  • 新建映射的时候就需使用ik分析器
  • ik_smart(最小) 和 ik_max_word(最细)的区别 举例分析程序员 ik_smart 会解析成程序员 ik_max_word 会解析成三个分别是 程序员 程序 员
{
  "mappings": {
    "db1": {
      "properties": {
        "content": {
          "type": "text",
          "store": true,
          "analyzer": "ik_smart"
        },
        "id": {
          "type": "long",
          "store": true
        },
        "title": {
          "type": "text",
          "store": true,
          "analyzer": "ik_max_word"
        }
      }
    }
  }
}

集群

修改config\elasticsearch.yml文件添加

#集群名称,保证唯一
cluster.name: my‐elasticsearch
#节点名称,必须不一样
node.name: node‐1 # node‐2 node‐3
#必须为本机的ip地址
network.host: 192.168.0.199 # 0.200  0.201
#服务端口号
http.port: 9200
#服务TCP端口号
transport.tcp.port: 9300
#设置集群自动发现机器ip集合
discovery.zen.ping.unicast.hosts:["192.168.0.199:9300","192.168.0.200:9300","192.168.0.201:9302"]

SpringBoot 整合

  • 创建工程 并引入依赖 内部引用的es版本必须要和服务器安装的匹配
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <version>2.3.10.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
  • application.yml配置
spring:
  elasticsearch:
    rest:
      uris: 192.168.0.199:9200
      username: my-application
  #   uris:192.168.0.199:9200,192.168.0.200:9200,192.168.0.201:9200,
  • 实体与document对应类
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;

@Document(indexName = "stu") //索引名称
@Data
public class Stu {
    @Id
    private Long stuId; //会创建相同的文档id 否则自动生成

    @Field(store = true)
    private String name;

    @Field(store = true)
    private Integer age;
}
  • 实体类中新加四个字段 会自动添加到索引里面
@Field(store = true)
private Float money;

@Field(store = true, type = FieldType.Keyword)
private String sign;

@Field(store = true)
private String description;

@Field(type = FieldType.Date, format = DateFormat.date_time)
private Date recordTime;
  • 关于常用方法 2.3.10 版本中的
@RunWith(SpringRunner.class)
@SpringBootTest
public class ESTest {
    /**
     * 一般不建议用Spring来创建/更新 删除索引
     * 一般针对文档进行CRUD操作
     */
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    /**
     * 创建/更新索引 如果存在 就更新 不会再创建 一般不使用
     */
    @Test
    public void createIndexStu() {
        Stu stu = new Stu();
        stu.setStuId(1006L);
        stu.setAge(33);
        stu.setName("李七");
        stu.setRecordTime(new Date());
        IndexQuery indexQuery = new IndexQueryBuilder().withObject(stu).build();
        IndexCoordinates indexCoordinates = elasticsearchRestTemplate.getIndexCoordinatesFor(Stu.class);
        elasticsearchRestTemplate.index(indexQuery, indexCoordinates);
    }

    /**
     * 更新文档
     */
    @Test
    public void updateStuDoc() {
        Document document = Document.create();
        document.put("name", "李四");
        document.put("age", 20);
        UpdateQuery updateQuery = UpdateQuery.builder("1000").withDocument(document).build();
        elasticsearchRestTemplate.update(updateQuery, elasticsearchRestTemplate.getIndexCoordinatesFor(Stu.class));
    }

    /**
     * 查询 + 高亮显示
     */
    @Test
    public void queryStuDoc() {
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        //必须满足的条件 加keyword不会拆分 不加会拆分成李和四
//        boolQueryBuilder.must().add(new TermQueryBuilder("name.keyword", "李四"));
//        boolQueryBuilder.must().add(new TermQueryBuilder("name", "四"));
        // 查询3天内数的数据
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("recordTime");
        rangeQueryBuilder.gte(LocalDateTime.now().minusDays(3));
//        或者下面的
//        rangeQueryBuilder
//                .from("2021-05-16T00:00:00.000Z")
//                .to("2021-05-19T23:59:59.000Z");
//        boolQueryBuilder.must().add(rangeQueryBuilder);


        // 分页查询20条
        PageRequest pageRequest = PageRequest.of(0, 20, Sort.by("stuId").descending());

        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        searchQueryBuilder
                .withQuery(boolQueryBuilder)
                // 亲测使用.keyword有值但是高亮数据size = 0
                .withHighlightBuilder(new HighlightBuilder().field("name")
                        .preTags("<font color='red'>")
                        .postTags("</font>"))
                .withPageable(pageRequest);


        Query searchQuery = searchQueryBuilder.build();

        SearchHits<Stu> result = elasticsearchRestTemplate.search(searchQuery, Stu.class);
        List<SearchHit<Stu>> hitList = result.getSearchHits();
        System.out.println("hit size -> {}" + hitList.size());
        hitList.forEach(hit -> {
            Map<String, List<String>> highlightFields = hit.getHighlightFields();
            List<String> nameHighlight = highlightFields.get("name");
            if (nameHighlight != null) {
                for (String text : nameHighlight) {
                    hit.getContent().setName(text);
                }
            }
            System.out.println("返回数据:" + hit.getContent().toString());
        });
    }

    /**
     * 删除文档
     */
    @Test
    public void delIndexDoc() {
        elasticsearchRestTemplate.delete("1000", elasticsearchRestTemplate.getIndexCoordinatesFor(Stu.class));
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容