01.ElasticSearch单机版及ELK安装springboot整合es

ElasticSearch

一. 简介

​ Elasticsearch是一个基于Apache Lucene™的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。

​ 但是,Lucene只是一个库。想要 使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。

​ Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。

​ Elasticsearch的中文网址:https://www.elastic.co/cn/products/elasticsearch

1.1 正向索引与倒排索引

​ 正向索引与倒排索引,这是在搜索领域中非常重要的两个名词,正向索引通常用于数据库中,在搜索引擎领域使用的最多的就是倒排索引,我们根据如下两个网页来对这两个概念进行阐述:

html1

我爱我的祖国,我爱编程

html2:

我爱编程,我是个快乐的小码农

**正向索引: ** 假设我们使用mysql的全文检索,会对如上两句话分别进行分词处理,那么预计得到的结果如下:

我 爱 爱我 祖国 我的祖国 编程 爱编程 我爱编程
我 我爱 爱 编程 爱编程 我爱编程 快乐 码农 小码农

​ 假设我们现在使用正向索引搜索 **编程 ** 这个词,那么会到第一句话中去查找是否包含有 编程 这个关键词,如果有则加入到结果集中;第二句话也是如此。假设现在有成千上百个网页,每个网页非常非常的分词,那么搜索的效率将会非常非常低些。

**倒排索引: ** 倒排索引是按照分词与文档进行映射,我们来看看如果按照倒排索引的效果:

关键词文档名
html1,html2,html3
html1,html2
爱我html1
我爱html2
祖国html1
我的祖国html1
编程html1,html2
我爱编程html1,html2
爱编程html1,html2
快乐html2
码农html2
小码农html2

​ 如果采用倒排索引的方式搜索 编程 这个词,那么会直接找到关键词中查找到 编程 ,然后查找到对应的文档,这就是所谓的倒排索引。正向索引是通过文档去查找单词,反向索引则是通过单词去查找文档。

倒排索引的优点还包括在处理复杂的多关键字查询时,可在倒排表中先完成查询的并、交等逻辑运算,得到结果后再对记录进行存取,这样把对文档的查询转换为地址集合的运算,从而提高查找速度

1.2 Elasticsearch概念以及产品

​ Elasticsearch中的索引的概念与数据库中索引的概念是完全不一样的,Elasticsearch中索引如果类比到数据库,那就是一个数据库名。

​ 文档在Elasticsearch中就是具体的数据,类比到数据库中那就是一条记录。

二. Elasticsearch环境搭建

​ 下载地址:https://www.elastic.co/cn/start,在下载页面我们需要下载 Elasticsearch和Kibana.

2.1 Elasticsearch的安装
2.1.1 单机版安装

​ 下载后解压进入到bin目录下,双击elasticsearch.bat,即可启动。在浏览器输入:http://localhost:9200/ 是否安装成功,如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5EtadvEm-1618057665851)(images/elasticsearch-success.png)]

2.1.2 集群安装 (了解)

​ Elasticsearch集群的安装非常的简单,只需要作一些简单的配置,修改配置文件 config/elasticsearch.yml。

​ 本节将采用两台节点来配置集群,一台是Windows操作系统,另外一台是Linux操作系统,将Windows操作系统下的Elasticsearch节点作为主节点。两台服务器的IP地址如下:

操作系统IP节点类型
Windows操作系统192.168.43.240主节点(master)
Linux操作系统192.168.223.139从节点(Slave)

主节点

  1. 修改C:\Windows\System32\drivers\etc\hosts文件,加入如下内容
192.168.43.240  master
  1. 修改Elasticsearch的config目录下的elasticsearch.yml文件,内容如下:
# 集群的名字
cluster.name: my-application
# 节点的名称
node.name: master
# 数据存放的位置
path.data: D:/elasticsearch-datas/to/data
# 日志存放的位置
path.logs: D:/elasticsearch-datas/to/logs
# 节点绑定的IP
network.host: 192.168.43.240
# 设置端口号
http.port: 9200
# 集群中所有的节点的ip地址
discovery.seed_hosts: ["192.168.43.240", "192.168.223.139"]
# 初始状态下集群中主节点的 node.name
cluster.initial_master_nodes: ["master"]
  1. 启动elasticsearch

从节点

  1. 创建elasticsearch用户,执行如下命令
useradd -m -s /bin/bash elasticsearch
  1. 给elasticsearch的主目录权限授予新创建的 elasticsearch 用户
chown -R elasticsearch /elasticsearch/
  1. 在 /etc/sysctl.conf 文件中加入如下内容
vm.max_map_count=262144  #加大虚拟内存空间,然后重启服务器

如果报以下错误,

max number of threads [3604] for user [elasticsearch] is too low, increase to at least [4096]

解决方案:修改 /etc/security/limits.conf 文件,在文件中加入如下内容:

*      soft     nproc 4096
*      hard     nproc 4096
  1. 在/etc/hosts目录下加入如下内容
192.168.43.240  master
  1. 修改Elasticsearch的config目录下的elasticsearch.yml文件,内容如下:
# 集群的名字
cluster.name: my-application
# 节点的名称
node.name: slave1
# 数据存放的位置
path.data: /elasticsearch-datas/to/data
# 日志存放的位置
path.logs: /elasticsearch-datas/to/logs
# 节点绑定的IP
network.host: 192.168.223.139
# 设置端口号
http.port: 9200
# 集群中所有的节点的ip地址
discovery.seed_hosts: ["192.168.43.240", "192.168.223.139"]
# 初始状态下集群中主节点的 node.name
cluster.initial_master_nodes: ["master"]
  1. 切换到elasticsearch用户,进入到elasticsearch的家目录下,执行如下命令
su - elasticsearch  #切换用户
bin/elasticsearch   #启动elasticsearch

集群监控

下载地址:https://github.com/lmenezes/cerebro/releases

直接双击cerebro家目录下的bin目录下的 cerebro.bat 即可启动,在浏览器地址栏访问:localhost:9000

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CMatREwi-1618057665853)(images/cerebro.png)]

在Node address输入:http://192.168.43.240:9200,然后点击 Connect 按钮

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EngJQl31-1618057665854)(images/cerebro-index.png)]

2.2 Kibana的安装

​ Kibana是世界上最受欢迎的开源日志分析平台ELK Stack中的“K” ,它为用户提供了一个工具,用于在存储于Elasticsearch集群中的日志数据进行检索,可视化和构建仪表板。

​ Kibana的核心功能是数据查询和分析。使用各种方法,用户可以搜索Elasticsearch中索引的数据,以查找其数据中的特定事件或字符串,以进行根本原因分析和诊断。基于这些查询,用户可以使用Kibana的可视化功能,允许用户使用图表,表格,地理图和其他类型的可视化以各种不同的方式可视化数据。

A. 下载后进入到家目录下的bin目录中,首先修改config目录下的kibana.yml文件,修改如下内容:

elasticsearch.hosts: ["http://192.168.43.240:9200", "http://192.168.223.139:9200"]

B. 进入bin目录下,双加 kibana.bat文件,在浏览器地址栏访问:http://localhost:5601

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dj6TvrMT-1618057665857)(images/kibana-index.png)]

C. Kibana中我们使用最多的就是 Dev Tools工具,来进行所有命令的演示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qOc23vTz-1618057665859)(images/kibana-dev-tools.png)]

注:如上 GET _cat/indices 命令是查看所有的索引。

2.3 Logstash的安装

​ Logstash是一个开源的服务器端数据处理管道,可以同时从多个数据源获取数据,并对其进行转换,然后将其发送到你最喜欢的“存储”。创建于2009年,于2013年被elasticsearch收购。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rxhc3mqT-1618057665860)(images/Logstash-logo.png)]

​ Logstash的下载地址:https://www.elastic.co/cn/downloads/logstash

A.下载测试数据集,下载地址:http://files.grouplens.org/datasets/movielens/,在该网页中下载ml-latest.zip

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PKozgoUa-1618057665861)(images/movies-datas.png)]

下载后解压目录,将movies.csv文件拷贝到指定的目录下,例如:D:/logstash-datas/ 目录。

B. 进入到Logstash的解压目录,进入到config目录下,新建logstash.conf,文件内容如下:

input {
  file {
    path => "D:/logstash-datas/movies.csv"
    start_position => "beginning"
    sincedb_path => "D:/elasticsearch/logstash-7.4.2/db_path.log"
  }
}
filter {
  csv {
    separator => ","
    columns => ["id","content","genre"]
  }

  mutate {
    split => { "genre" => "|" }
    remove_field => ["path", "host","@timestamp","message"]
  }

  mutate {

    split => ["content", "("]
    add_field => { "title" => "%{[content][0]}"}
    add_field => { "year" => "%{[content][1]}"}
  }

  mutate {
    convert => {
      "year" => "integer"
    }
    strip => ["title"]
    remove_field => ["path", "host","@timestamp","message","content"]
  }

}
output {
   elasticsearch {
     hosts => "http://localhost:9200"
     index => "movies"
     document_id => "%{id}"
   }
  stdout {}
}

C. 在命令行进入到logstash的bin目录下,输入如下命令启动Logstash:

logstash.bat -f D:\elasticsearch\logstash-7.4.2\config\logstash.conf

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gzYmcADC-1618057665862)(images/logstash-startup-command.png)]

特别强调:路径中绝对不能有中文。

D. 在Kibana的Dev Tools中执行 GET _cat/indices, 即可查看到movies数据集:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mzSwLm9l-1618057665863)(images/kibana-movies-datas.png)]

三. Elasticsearch的基本概念

3.1 索引、文档、类型

索引

Elasticsearch中的索引有多层的意思:a. 某一类文档的集合就构成了一个索引,类比到数据库就是一个数据库(或者数据库表);b.它还描述了一个动作,就是将某个文档保存在elasticsearch的过程也叫索引;c. 倒排索引。

文档

具体的一条数据,类比到数据库就是一条记录。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dx7IFTvk-1618057665864)(images/index-documnet.png)]

类型

在7.0之前,一个Index可以创建多个类型,从7.0开始,一个索引只能创建一个类型,也就是_doc

DBMSElasticsearch
databaseIndex
tabletype(在7.0之后type为固定值_doc)
RowDocument
ColumnField
SchemaMapping
SQLDSL(Descriptor Structure Language)

四. RestAPI

查询所有的索引

GET _cat/indices

查询movies的信息

GET movies

查询movies的记录总数

GET movies/_count

查询movies的前几条数据

GET movies/_search
4.1 基本CRUD

A. 添加数据,没有指定ID, 系统会生成ID

POST user/_doc
{
  "age": 10,
  "firstName": "Will",
  "lastName": "Smith"
}

然后查询:GET user/_search

B. 操作数据,指定ID,如果有对应的ID,就修改数据;如果没有对应的ID,就添加数据

POST user/_doc/1
{
  "age": 20,
  "firstName": "Roden",
  "lastName": "Jhson"
}

C. 通过 _create 的方式,如果存在ID,就会报错

POST user/_create/2
{
  "age": 40,
  "firstName": "Douge",
  "lastName": "Lee"
}

PUT user/_create/8 
{
  "age": 50,
  "firstName":"Jacks",
  "lastName": "Lily"
}

D. 查询指定ID的文档

GET user/_doc/1

E. 删除指定ID的文档

DELETE user/_doc/2Gxqc24BJqcwPamzqWgn

F. 指定ID,创建或者覆盖

PUT user/_doc/1
{
  "age": 40,
  "firstName": "Hello",
  "lastName": "Lee"
}

G. 修改原有数据的结构

POST user/_update/1
{
  "doc": {
    "firstName":"Rodan",
    "lastName": "Johson"
  }
}

H.批量查询

GET _mget
{
  "docs": [
    {"_index":"movies", "_id":"104372"},
   {"_index":"movies", "_id":"104374"}
  ]
}

I. 分页查询

GET movies/_search
{
  "from": 0,
  "size": 20
}

J. 批量插入(可以指定ID,也可以不指定ID)

POST user/_bulk
{"index":{"_id": 23}}
{"firstName":"Will", "lastName":"Smith", "mobile": "123455"}
{"index":{}}
{"firstName":"Lily", "lastName":"Bob", "mobile": "98765"}
4.2 URI查询

泛查询,就是不指定字段,全字段查找,如下查找所有字段中包含有2012的电影

GET movies/_search?q=2012

查询title中包含有2012的所有的电影(df是default field)

GET movies/_search?q=2012&df=title
或者
GET movies/_search?q=title:2012

查询title中包含有2012,取索引从10开始,共8条数据

GET movies/_search?q=title:2012&from=10&size=8

字符串判断查询:

# 查询titile中包含有Beautiful, Mind
GET movies/_search?q=title:Beautiful Mind

#查询title中包含有Beautiful, 并且年份大于2012
GET movies/_search?q=title:Beautiful AND year:>=2012

#查询titile中包含有Beautiful或者Mind
GET movies/_search?q=title:(Beautiful Mind)
GET movies/_search?q=title:(+Mind +Beautiful)

#查询title中包含有“Beautiful Mind”的所有的电影
GET movies/_search?q=title:"Beautiful Mind"


#查询title中既包含有Mind又包含有Beautiful的所有的电影,对先后顺序没有要求
GET movies/_search?q=title:(Mind AND Beautiful)
GET movies/_search?q=title:(+Mind AND +Beautiful)

#查询title中包含Mind但是不包含Beautiful的所有的电影
GET movies/_search?q=title:(Mind NOT Beautiful)
GET movies/_search?q=title:(Mind -Beautiful)

年份判断查询:

#查询2018年以后上映的电影
GET movies/_search?q=year:>=2018

#查询2012年到2017年上映的电影
GET movies/_search?q=year:(>=2012 AND <2018)

#查询2016年到2017年所有的电影,注意:必须以 ] 结尾
GET movies/_search?q=year:{2015 TO 2017]

正则判断查询:

#查询title中以Mi开头,中间包含一个字符,以d结尾的所有的电影
GET movies/_search?q=title:Mi?d

#查询title中以Min开头,后面为任何内容的电影
GET movies/_search?q=title:Min*
4.3 Request Body查询

​ 在有些查询中,可能会用到各种特别复杂的查询,那么就需要使用Request Body查询。

A.以year的倒序排序,查询电影年份在 [2017, 2018]的数据, query只能单条件查询

GET movies/_search
{
  "sort": [
    {
      "year": {
        "order": "desc"
      }
    }
  ],
  # query中只能有一个条件
  "query": {
    "range": {
      "year": {
        "gte": 2017,
        "lte": 2018
      }
    }
  }
}

B.以year的倒序排序,查询titile中包含有Beautiful或者Mind的数据, query只能单条件查询

GET movies/_search
{
  "sort": [
    {
      "year": {
        "order": "desc"
      }
    }
  ],
  # query中只能有一个条件
  "query": {
    "match": {
      "title": "Beautiful Mind"
    }
  }
}

C. 按照年份的倒序,分页查询

GET movies/_search
{
  "sort": [
    {
      "year": {
        "order": "desc"
      }
    }
  ],
  "from": 0,
  "size": 20
}

D. 短语匹配,查询title中包含有 “Beautiful Mind” 这个短语的的电影

GET movies/_search
{
  "query": {
    "match_phrase": {
      "title": "Beautiful Mind"
    }
  }
}

E. 只查询部分列

GET movies/_search
{
  "_source": ["title", "year"]
}

F. 多个条件查询,多条件查询必须使用bool

GET movies/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "year": {
              "gte": 2017,
              "lte": 2018
            }
          }
        },
        {
          "match": {
            "title": "Beautiful Mind"
          }
        }
      ]
    }
  }
}

G. 多字段同时匹配某些字符串

GET movies/_search
{
  "query": {
    "multi_match": {
      "query": "beautiful mind Romance",
      "fields": ["title", "genre"],
      "type": "best_fields"
    }
  }
}

其中type的值有三个:

  • most_fields:在多字段中匹配的越多排名越靠前
  • best_fields: 能完全匹配的文档,排名越靠前。
  • cross_fields: 查询越分散,排名越靠前。

H. query_string 的用法

GET movies/_search
{
  "query": {
    "query_string": {
      "default_field": "title",
      "query": "Beautiful Mind",
      "default_operator": "AND"   #不加默认是OR
    }
  }
}
GET movies/_search
{
  "query": {
    "query_string": {
      "fields": ["title", "genre"],
      "query": "Beautiful Mind",
      "default_operator": "AND"
    }
  }
}

I. term实现精准匹配,查询title为Beautiful Mind 的电影

GET movies/_search
{
  "query": {
    "term": {
      "title.keyword": {
        "value": "Beautiful Mind, A"
      }
    }
  }
}

J. 多条件或者判断(should表示或者,must表示必须)

GET movies/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "title": "Beautiful Mind"
          }
        },
        {
          "range": {
            "year": {
              "gte": 2017,
              "lte": 2018
            }
          }
        }
      ]
    }
  }
}

K. 推荐搜索

GET movies/_search
{
  "suggest": {
    "title-suggest": {
      "text": "minx",
      "term": {
        "field": "title",
        "suggest_mode": "missing"
      }
    }
  }
}	
GET movies/_search
{
  "suggest": {
    "title-suggest": {
      "text": "mine",
      "term": {
        "field": "title",
        "suggest_mode": "popular"
      }
    }
  }
}
GET movies/_search
{
  "suggest": {
    "title-suggest": {
      "text": "minx",
      "term": {
        "field": "title",
        "suggest_mode": "always"
      }
    }
  }
}

所谓的推荐搜索就是当我们根据条件搜索的时候,因为单词的拼写错误,但是无法搜索出结果,那么Elasticsearch会给出一定的搜索建议,通过 sugguest 来实现。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-95V4kN36-1618057665865)(images/search-suggest.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-epmuCbDF-1618057665866)(images/search-suggest-result.png)]

我们说一下suggest_mode 的三种模式:missingpopularalways

**missing: ** 意思是当词典中没有找到对应的索引信息,才去推荐。

**popular: ** 意思是即使我们去搜索一个被索引了的单词,但是还是会去给我们推荐类似的但是出现频率很高的词。

**always: ** 无论在任何情况下,都给出推荐。

4.5 自动补全功能

​ Elasticsearch的自动补全功能是基于 suggest 来实现的,但是需要提前定义好需要进行搜索字段的mapping信息(mapping一旦创建好后是不能修改的)。

A. 使用 GET movies 命令查看,定义mapping并执行,设置自动补全的属性的 type 必须是 completion

{"mappings" : {
   "properties" : {
      "@version" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "genre" : {
        "type" : "completion",  
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "id" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
     },
     "title" : {
        "type" : "completion",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "year" : {
        "type" : "long"
      }
    }
  }
}

B.执行如下命令,先删除movies,再重新定义mapping

DELETE movies
PUT movies
  {"mappings" : {
   "properties" : {
      "@version" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "genre" : {
        "type" : "completion",  
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "id" : {
        "type" : "text",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
     },
     "title" : {
        "type" : "completion",
        "fields" : {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      },
      "year" : {
        "type" : "long"
      }
    }
  }
}

C. 删除 logstash 的配置文件 db_path.log,然后再执行 logstash 命令,重新导入 movies 数据集

logstash.bat -f D:\elasticsearch\logstash-7.4.2\config\logstash.conf

D. 执行推荐 min表示前缀

GET movies/_search
{
  "suggest": {
    "title-suggest": {
      "prefix": "min",
      "completion": {
        "field": "title",
        "skip_duplicates": true #忽略重复
      }
    }
  }
}

不足:completion这个推荐的方式只能是前缀查询,但是其查找速度极快。

E. Java代码实现自动补全功能,类似HTML中的 autocomplete 属性

elasticsearch与springboot整合实现步骤:

1.创建springboot项目,导入依赖( 注:不同版本的springboot对应elasticsearch版本也不同 )

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2.创建配置类 ( 此次使用的是 springboot是2.3.X 版本,默认匹配7.6.X的elasticsearch )

package com.qf.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;

@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {

    @Bean
    public RestHighLevelClient elasticsearchClient() {

        // 两种方式获取 RestHighLevelClient(elasticsearch高端查询对象)
        // spring官网
//        final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
//            .connectedTo("localhost:9200")
//            .build();
//        return RestClients.create(clientConfiguration).rest();

        // elasticsearch官网
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));

        return client;

    }

    // 获取ElasticsearchRestTemplate模版对象(elasticsearch 6.x 使用的是ElasticsearchTemplate对象)
    @Bean
    public ElasticsearchRestTemplate elasticsearchRestTemplate() {
        return new ElasticsearchRestTemplate(elasticsearchClient());
    }
}

3.创建实体类

package com.qf.pojo;

import lombok.Data;
import org.springframework.data.elasticsearch.annotations.Document;

import java.util.List;

@Document(indexName = "movies")
@Data
public class Movie {
    private String id;
    private String title;
    private Integer year;
    private List<String> genre;

}

4.创建MovieController查询所有

package com.qf.controller;

import com.qf.pojo.Movie;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("movie")
public class MovieController {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @GetMapping("findAll")
    public List<Movie> findAll(){

        //指定查询条件并获取查询对象
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(
                new RangeQueryBuilder("year").from(2017, true)
                        .to(2018, true)
        ).build();

        //获取查询命中结果封装到实体类对象中
        SearchHits<Movie> searchHits =
                elasticsearchRestTemplate.search(nativeSearchQuery, Movie.class, IndexCoordinates.of("movies"));

        //获取查询命中的结果集
        List<SearchHit<Movie>> searchHitList = searchHits.getSearchHits();

        //创建集合并保存数据
        ArrayList<Movie> list = new ArrayList<Movie>(searchHitList.size());

        for(SearchHit<Movie> movieSearchHit:searchHits){
            Movie movie=movieSearchHit.getContent();
            list.add(movie);
        }

        //返回数据
        return list;
    }
}

5.浏览器访问controller进行测试

6.创建建议搜索MovieSuggestSearchContorller

package com.qf.controller;

import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("movie-suggest")
public class MovieSuggestSearchContorller {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @GetMapping("findAll")
    public Object movieSuggest(String text){

//        GET movies/_search
//        {
//            "suggest": {
//            "title-suggest": {
//                "prefix": "min",
//                    "completion": {
//                    "field": "title",
//                    "skip_duplicates": true
//                }
//            }
//        }
//        }

        //推荐查询参数设置
        CompletionSuggestionBuilder completionSuggestionBuilder =
                new CompletionSuggestionBuilder("title")
                .prefix(text).size(10);//设置输入推荐搜索的前缀值和显示数量
                .skipDuplicates(true);//忽略重复

        //设置suggest中标识的名字(任意名字,但需要和Suggestion中一致)
        SuggestBuilder suggestBuilder = new SuggestBuilder()
            .addSuggestion("suggest_movie", completionSuggestionBuilder);

        //指定要查询的索引
        SearchResponse response=elasticsearchRestTemplate.suggest(suggestBuilder, IndexCoordinates.of("movies"));

        //获取Suggest对象
        Suggest suggest = response.getSuggest();

        //获取对应的建议搜索的结果
        Suggest.Suggestion suggestion = suggest.getSuggestion("suggest_movie");

		//创建集合来抓取建议搜索出来自动补全的结果集
        Set<String> suggestResult = new HashSet<String>();
		//获取结果集
        List entries = suggestion.getEntries();
        if(entries.size()>0 && entries!=null){
            Object object = entries.get(0);

            if( object instanceof CompletionSuggestion.Entry){
                CompletionSuggestion.Entry entry = (CompletionSuggestion.Entry)object;

                List <CompletionSuggestion.Entry.Option> options = entry.getOptions();
                if(options!=null && options.size()>0){
                    for(CompletionSuggestion.Entry.Option option : options){
                        suggestResult.add(option.getText().toString());
                    }
                }
            }
        }

        return suggestResult;

    }

}

访问浏览器:http://localhost:8080/movie-suggest/findAll?text=min 进行测试

chResponse response=elasticsearchRestTemplate.suggest(suggestBuilder, IndexCoordinates.of(“movies”));

    //获取Suggest对象
    Suggest suggest = response.getSuggest();

    //获取对应的建议搜索的结果
    Suggest.Suggestion suggestion = suggest.getSuggestion("suggest_movie");

	//创建集合来抓取建议搜索出来自动补全的结果集
    Set<String> suggestResult = new HashSet<String>();
	//获取结果集
    List entries = suggestion.getEntries();
    if(entries.size()>0 && entries!=null){
        Object object = entries.get(0);

        if( object instanceof CompletionSuggestion.Entry){
            CompletionSuggestion.Entry entry = (CompletionSuggestion.Entry)object;

            List <CompletionSuggestion.Entry.Option> options = entry.getOptions();
            if(options!=null && options.size()>0){
                for(CompletionSuggestion.Entry.Option option : options){
                    suggestResult.add(option.getText().toString());
                }
            }
        }
    }

    return suggestResult;

}

}


>访问浏览器:http://localhost:8080/movie-suggest/findAll?text=min 进行测试

>导入静态资源,再次访问页面进行测试
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值