ElasticSearch搜索引擎
文章目录
- ElasticSearch搜索引擎
- 学习目标
- 1.ElasticSearche
- 1.1 全文检索
- 1.2 索引结构
- 1.3 ElasticSearch
- 1.3.1 ElasticSearch介绍
- 1.4 使用postman操作索引库
- 1.4.1 新建文档
- 1.4.2 查询文档
- 1.5 映射和数据类型
- 1.5.1 字符串类型
- 1.5.2 整数类型
- 1.5.3 浮点类型
- 1.5.4 date类型
- 1.5.5 boolean 类型
- 1.5.6 binary类型
- 1.5.7 array类型
- 1.5.8 object类型
- 1.6 IK分词器
- 1.6.1 默认中文分词器
- 1.6.2 IK中文分词器
- 1.6.3 IK分词器之自定义词库
- 1.7 Kibana
- 1.7.1 Kibana介绍
- 1.7.2 Kibana安装启动
- 2.索引操作
- 2.1 创建索引与映射字段
- 2.2 文档增加与修改
- 2.2.1 增加文档自动生成ID
- 2.2.2 新增文档指定ID
- 2.3 `*****`索引查询 `*****
- 2.3.1 查询所有数据(match_all)
- 2.3.2 匹配查询(match)
- 2.3.3 多字段查询(multi_match)
- 2.3.4 词条匹配(term)
- 2.3.5 多词条匹配(terms)
- 2.3.6 布尔组合(bool)
- 2.3.7 过滤查询
- 2.3.8 分组查询
- 3.使用Java操作索引
- 3.1 简介
- 3.2 Java操作ElasticSearch中的Index索引
- 3.2.1 新增和修改数据
- 3.2.2 匹配查询
- 3.2.3 布尔与词条查询
- 3.2.4 过滤查询
- 3.2.5 分组(聚合查询)
学习目标
- 理解elasticsearch索引结构和数据类型,掌握IK分词器的使用
- 掌握索引的常用操作(使用Kibana工具)
- 掌握javaRest高级api
- 完成数据批量导入
1.ElasticSearche
1.1 全文检索
如何能正确的显示出用户想要的商品,并进行合理的过滤,尽快促成交易,是搜索系统要研究的核心。面对这样复杂的搜索业务和数据量,使用传统数据库搜索就显得力不从心,一般我们都会使用全文检索技术。 常见的全文检索技术有 Lucene、solr 、elasticsearch 等。
1.2 索引结构
下边黑色部分是物理结构,上边黄色部分是逻辑结构,逻辑结构也是为了更好的去描述工作原理及去使用物理结构中的索引文件。
逻辑结构部分是一个倒排索引表:
1、将要搜索的文档内容分词,所有不重复的词组成分词列表。
2、将搜索的文档最终以Document方式存储起来。
3、每个词和docment都有关联。
如下:
现在,如果我们想搜索 quick brown
,我们只需要查找包含每个词条的文档
两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配 词条数量的简单 相似性算法 ,那么,我们可以说,对于我们查询的相关性来讲,第一个 文档比第二个文档更佳。
1.3 ElasticSearch
1.3.1 ElasticSearch介绍
ElasticSearch是一个基于Lucene的搜索服务器,提供了一个分布式多用户能力的全文搜索引擎,提供了RestFul web 接口,便于操作使用。用java开发的,开源免费的。
官网地址:https://www.elastic.co/cn/products/elasticsearch
GitHub:https://github.com/elastic/elasticsearch
学习使用的是elasticsearch 6.5.2
优点:
- 可作为大型分布式几圈技术,处理PB级别数据,服务大公司,同时也可以允许在单机上。
- 把全文检索、数据分析以及分布式技术合并在一起。形成独一无二的ES;
- 开箱即用,部署简单
- 全文检索、同义词处理、相关排名、复杂数据分析、海量数据的近实时处理
是Elasticsearch与MySQL数据库逻辑结构概念的对比
ElasticSearch | 关系型数据库MySQL |
---|---|
索引(Index) | 数据库(DataBases) |
类型(Type) | 表(Table) |
文档(Document) | 行(Row) |
一般我们会这样操作:一个索引库里面只有一种类型。
下载地址:https://www.elastic.co/cn/downloads/past-releases/
无需安装,解压安装包后即可使用
在命令提示符下,进入ElasticSearch安装目录下的bin目录,执行命令
代码语言:javascript复制elasticsearch
即可启动.
在浏览器中输入:http://127.0.0.1:9200既可以看到输出结果。
代码语言:javascript复制{
"name" : "lB-loiZ",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "p_DyfvICQuS8fGcEpDUZjw",
"version" : {
"number" : "6.5.2",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "9434bed",
"build_date" : "2018-11-29T23:58:20.891072Z",
"build_snapshot" : false,
"lucene_version" : "7.5.0",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
1.4 使用postman操作索引库
1.4.1 新建文档
使用postman测试:以post方式提交 http://127.0.0.1:9200/testindex/doc
body:
代码语言:javascript复制{
"name":"测试商品",
"price":123
}
POST请求方式:http://localhost:9200/索引名称/索引类型/ 参数为json类型
如果索引、类型不存在elasticsearch会自动进行创建。
返回结果:
代码语言:javascript复制{
"_index": "testindex",//表示索引库
"_type": "doc",//类型为doc
"_id": "QXDM724BgQEvCDLHV5pO",
"_version": 1, //该id下记录数据更改次数.
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
_id是由系统自动生成的。
elasticsearch可以在不建立结构下直接加入数据,添加数据之后,
可以根据添加的数据的类型,自动创建索引库、类型以及相应的字段。
1.4.2 查询文档
代码语言:javascript复制Get请求:http://localhost:9200/testindex/doc/_search
返回结构
代码语言:javascript复制{
"took": 78,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 4,
"max_score": 1.0,
"hits": [
{
"_index": "testindex",
"_type": "doc",
"_id": "RHDX724BgQEvCDLH2pqw",
"_score": 1.0, //分值、匹配度 _search 简单搜索。
"_source": {
"name": "苹果电脑",
"price": 5500
}
},
{
"_index": "testindex",
"_type": "doc",
"_id": "QXDM724BgQEvCDLHV5pO",
"_score": 1.0,
"_source": {
"name": "测试商品",
"price": 123
}
},
{
"_index": "testindex",
"_type": "doc",
"_id": "Q3DX724BgQEvCDLHs5rc",
"_score": 1.0,
"_source": {
"name": "苹果手机",
"price": 3500
}
},
{
"_index": "testindex",
"_type": "doc",
"_id": "QnDX724BgQEvCDLHZpqb",
"_score": 1.0,
"_source": {
"name": "华为手机",
"price": 1500
}
}
]
}
}
1.5 映射和数据类型
映射(Mapping)相当于数据表的表结构。ElasticSearch中的映射(Mapping)用来
定义一个文档,可以定义所包含的字段以及字段的类型、分词器及属性等等。
映射可以分为动态映射和静态映射。
- 动态映射 (dynamic mapping):在关系数据库中,需要事先创建数据库,然后在
该数据库实例下创建数据表,然后才能在该数据表中插入数据。而ElasticSearch中不需
要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类
型,这种机制称之为动态映射。
- 静态映射 :在ElasticSearch中也可以事先定义好映射,包含文档的各个字段及其类
型等,这种方式称之为静态映射。
1.5.1 字符串类型
类型 | 描述 |
---|---|
text | 当一个字段是要被全文搜索的,比如Email内容、产品描述,应该使用 text类型。设置text类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个 一个词项。text类型的字段不用于排 序,很少用于聚合。 |
keyword | keyword类型适用于索引结构化的字段,比如email地址、主机名、状 态码和标签。如果字段需要进行过滤(比如查找已发布博客中status属性 为published的文章)、排序、聚合。keyword类型的字段只能通过精确值搜索到。 |
1.5.2 整数类型
类型 | 取值范围 |
---|---|
byte | -128~127 |
short | -32768~32767 |
integer | -231~231-1 |
long | -263~263-1 |
1.5.3 浮点类型
类型 | 取值范围 |
---|---|
double | 64位双精度浮点类型 |
float | 32位单精度浮点类型 |
half_float | 16位单精度浮点类型 |
scaled_float | 缩放类型的浮点数 |
1.5.4 date类型
日期类型表示格式可以是以下几种:
(1)日期格式的字符串,比如 “2018-01-13” 或 “2018-01-13 12:10:30”
(2)long类型的毫秒数( milliseconds-since-the-epoch,epoch就是指UNIX诞生的UTC 时间1970年1月1日0时0分0秒)
(3)integer的秒数(seconds-since-the-epoch)
1.5.5 boolean 类型
逻辑类型(布尔类型)可以接受true/false
1.5.6 binary类型
二进制字段是指用base64来表示索引中存储的二进制数据,可用来存储二进制形式
的数据,例如图像。默认情况下,该类型的字段只存储不索引。二进制类型只支持
index_name属性。
1.5.7 array类型
在ElasticSearch中,没有专门的数组(Array)数据类型,但是,在默认情况下,任意一个字段都可以包含0或多个值,这意味着每个字段默认都是数组类型,只不过,数组类型的各个元素值的数据类型必须相同。在ElasticSearch中,数组是开箱即用的(out of box),不需要进行任何配置,就可以直接使用。
在同一个数组中,数组元素的数据类型是相同的,ElasticSearch不支持元素为多个数据类型:[ 10, “some string” ],
常用的数组类型是:
(1)字符数组: [ “one”, “two” ]
(2)整数数组: productid:[ 1, 2 ]
(3)对象(文档)数组: “user”:[ { “name”: “Mary”, “age”: 12 }, { “name”: “John”, “age”: 10 }],ElasticSearch内部把对象数组展开为 {“user.name”: [“Mary”, “John”], “user.age”: [12,10]}
1.5.8 object类型
JSON天生具有层级关系,文档会包含嵌套的对象
1.6 IK分词器
1.6.1 默认中文分词器
使用postman测试 post方式提交
代码语言:javascript复制http://127.0.0.1:9200/testindex/_analyze
//指定分词器 :analyzer:chinese
{"analyzer": "chinese", "text": "java程序员" }
返回结果:
代码语言:javascript复制{
"tokens": [
{
"token": "java",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "程",
"start_offset": 4,
"end_offset": 5,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "序",
"start_offset": 5,
"end_offset": 6,
"type": "<IDEOGRAPHIC>",
"position": 2
},
{
"token": "员",
"start_offset": 6,
"end_offset": 7,
"type": "<IDEOGRAPHIC>",
"position": 3
}
]
}
默认的中文分词是将每个字看成一个词,所以需要安装一个中文分词器来解决问题.IK中文分词器。
1.6.2 IK中文分词器
下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases 下载6.5.2版
(1)先将其解压,将解压后的elasticsearch文件夹重命名文件夹为ik
(2)将ik文件夹拷贝到elasticsearch/plugins 目录下。
(3)重新启动,即可加载IK分词器
IK分词有两种算法
- 最小切分
使用postman测试 post方式提交
代码语言:javascript复制http://localhost:9200/testindex/_analyze
代码语言:javascript复制{
"analyzer":"ik_smart",
"text":"java程序员"
}
返回结果:
代码语言:javascript复制{
"tokens": [
{
"token": "java",
"start_offset": 0,
"end_offset": 4,
"type": "ENGLISH",
"position": 0
},
{
"token": "程序员",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 1
}
]
}
- 最细切分
使用postman测试 post方式提交
代码语言:javascript复制http://localhost:9200/testindex/_analyze
代码语言:javascript复制{
"analyzer":"ik_max_word",
"text":"java程序员"
}
返回结果:
代码语言:javascript复制{
"tokens": [
{
"token": "java",
"start_offset": 0,
"end_offset": 4,
"type": "ENGLISH",
"position": 0
},
{
"token": "程序员",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 1
},
{
"token": "程序",
"start_offset": 4,
"end_offset": 6,
"type": "CN_WORD",
"position": 2
},
{
"token": "员",
"start_offset": 6,
"end_offset": 7,
"type": "CN_CHAR",
"position": 3
}
]
}
1.6.3 IK分词器之自定义词库
在测试”传智播客”,
使用postman测试 post方式提交
代码语言:javascript复制http://localhost:9200/testindex/_analyze
代码语言:javascript复制{
"analyzer":"ik_max_word",
"text":"传智播客"
}
返回结果:
代码语言:javascript复制{
"tokens": [
{
"token": "传",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
},
{
"token": "智",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 1
},
{
"token": "播",
"start_offset": 2,
"end_offset": 3,
"type": "CN_CHAR",
"position": 2
},
{
"token": "客",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 3
}
]
}
默认的分词并没有识别“ 传智播客”是一个词。如果我们想让系统识别“传智播客”是一个词,需要编辑自定义词库。
步骤:
(1)进入elasticsearch/plugins/ik/config目录
(2)新建一个my.dic文件,编辑内容:
代码语言:javascript复制传智播客
文本文件要使用UTF-8编码格式
修改IKAnalyzer.cfg.xml(在ik/config目录下)
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">my.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
<!--用户可以在这里配置远程扩展字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--用户可以在这里配置远程扩展停止词字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
重新启动elasticsearch,通过浏览器测试分词效果
代码语言:javascript复制{
"tokens": [
{
"token": "传智播客",
"start_offset": 0,
"end_offset": 4,
"type": "CN_WORD",
"position": 0
}
]
}
1.7 Kibana
1.7.1 Kibana介绍
Kibana 是一个开源的分析和可视化平台,旨在与 Elasticsearch 合作。Kibana 提供
搜索、查看和与存储在 Elasticsearch 索引中的数据进行交互的功能。开发者或运维人员
可以轻松地执行高级数据分析,并在各种图表、表格和地图中可视化数据。
1.7.2 Kibana安装启动
(1)解压 资料配套软件elasticsearchkibana-6.5.2-windows-x86_64.zip
(2)如果Kibana远程连接Elasticsearch ,可以修改configkibana.yml
(3)执行binkibana.bat
(4)打开浏览器,键入http://localhost:5601 访问Kibana
2.索引操作
2.1 创建索引与映射字段
语法
请求方式依然是PUT
代码语言:javascript复制PUT /索引库名
{
"mappings": {
"类型名称":{
//类似于数据库中的不同表字段名:任意填写 ,相当于表的名称。
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"//比如ik_max_word
}
}
}
}
- 类型名称:类似于数据库中的不同表字段名:任意填写,可以指定许多属性,例如:
- type:类型,可以是text、long、short、date、integer、object等
- index:是否索引,默认为true ,比如商品图片,就可以不用设置成索引进行搜索
- store:是否单独存储,默认为false ,一般内容比较多的字段设置成true,可提升查询性能
- analyzer:分词器
#创建索引结构
PUT sku {
"mappings": {
"doc":{
"properties":{
"name":{
"type":"text",
"analyzer":"ik_smart"
},
"price":{
"type":"integer"
},
"image":{
"type":"text",
"index":false
},
"createTime":{
"type":"date"
},
"spuId":{
"type":"text"
},
"categoryName":{
"type":"keyword"
},
"brandName":{
"type":"keyword"
},
"spec":{
"type":"object"
},
"saleNum":{
"type":"integer"
},
"commentNum":{
"type":"integer"
}
}
}
}
}
把要查询的信息进行建立索引。
代码语言:javascript复制sku id == _id //使用elasticsearch的自动创建的id
商品名称 需要进行分词 text
商品价格 integer
商品图片 不需要索引 text
创建时间 data
spu id text
商品分类 keyword (需要进行聚合操作)
品牌 keyword
规格 object(数据库中存储的是一个json对象{"颜色":"红色","网络":"5G"},使用Object类型,在添加数据的时候也是使用json格式)
销量 Integer
评价 text
响应结果
代码语言:javascript复制{
"acknowledged": true, //表示生成成功。
"shards_acknowledged": true,
"index": "sku"
}
2.2 文档增加与修改
2.2.1 增加文档自动生成ID
通过POST请求,可以向一个已经存在的索引库添加数据
代码语言:javascript复制语法格式
POST 索引库名/ 类型名
{
"key":"value"
}
代码语言:javascript复制比如:
### 插入文档
POST sku/doc
{
"name":"小米手机",
"price":200000,
"spuId":101,
"createTime":"2019-05-01",
"brandName":"小米",
"categerName":"手机",
"saleNum":1203,
"commentNum":2356,
"spec":{
"网络制式":"移动4G",
"屏幕尺寸":"4.5"
}
}
代码语言:javascript复制响应结果
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",//在添加文档的时候,不指定id,elasticsearch会自动生成
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
代码语言:javascript复制通过以下命令查询sku索引的数据
GET sku/_search
代码语言:javascript复制响应结果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : 101,
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.2.2 新增文档指定ID
代码语言:javascript复制语法
PUT 索引库名/类型/id值
{
"key":"value"
}
代码语言:javascript复制比如
###新增文档指定id
PUT sku/doc/1
{
"name":"华为手机",
"price":400000,
"spuId":"102",
"createTime":"2019-05-01",
"brandName":"华为",
"categerName":"手机",
"saleNum":1403,
"commentNum":2656,
"spec":{
"网络制式":"全网通",
"屏幕尺寸":"6.5"
}
}
代码语言:javascript复制相应结果
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
代码语言:javascript复制再次使用GET sku/_search 得到的结果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "华为手机",
"price" : 400000,
"spuId" : "102",
"createTime" : "2019-05-01",
"brandName" : "华为",
"categerName" : "手机",
"saleNum" : 1403,
"commentNum" : 2656,
"spec" : {
"网络制式" : "全网通",
"屏幕尺寸" : "6.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
代码语言:javascript复制修改文档(可以更具id进行修改)
比如: 修改华为手机的评论数
PUT sku/doc/1
{
"name":"华为手机",
"price":400000,
"spuId":"102",
"createTime":"2019-05-01",
"brandName":"华为",
"categerName":"手机",
"saleNum":1403,
"commentNum":12656,
"spec":{
"网络制式":"全网通",
"屏幕尺寸":"6.5"
}
}
代码语言:javascript复制相应结果中的”result”变成”updated”
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
可以使用 GET sku/_search 进行查看修改的结果。华为手机的评论数发生改变。
2.3 *****
索引查询 *****
代码语言:javascript复制基本语法
GET 索引库名/_search
{
"query":{
"查询类型":{
"查询条件":"查询条件值"
}
}
}
query
代表一个查询对象,里面可以有不同的查询属性
- 查询类型
match_all
、match
、term(根据字段)
、range(根据区间)
、等。
- 查询条件:查询条件会根据类型的不同,写法也有差异。比如
bool
、过滤查询/分组查询
2.3.1 查询所有数据(match_all)
代码语言:javascript复制GET sku/_search
{
"query":{
“match_all”:{
}
}
}
query
:代表查询对象match_all
:代表查询所有
上面查询所有的简化版写法GET sku/_search
- took:查询花费时间,单位是毫秒
- time_out:是否超时
- _shards:分片信息
- hits:搜索结果总览对象
- total:搜索到的总条数
- max_score:所有结果中文档得分的最高分
- -hits:搜索结果的文档对象数组,每个元素是一条搜索到的文档信息
- _index:索引库
- _type:文档类型
- _id:文档id
- _score:文档得分
- _source:文档的源数据
2.3.2 匹配查询(match)
查询名称包含手机
代码语言:javascript复制###查询名称包含手机
GET sku/_search
{
"query": {
"match": {
"name": "手机"
}
}
}
代码语言:javascript复制查询结果
{
"took" : 23,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.6931472,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 0.6931472,
"_source" : {
"name" : "三星手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"name" : "华为手机",
"price" : 400000,
"spuId" : "102",
"createTime" : "2019-05-01",
"brandName" : "华为",
"categerName" : "手机",
"saleNum" : 1403,
"commentNum" : 12656,
"spec" : {
"网络制式" : "全网通",
"屏幕尺寸" : "6.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 0.2876821,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
查询“小米电视”
看到结果为小米电视、三星电视、小米手机三条结果,这是为什么呢?这是因为在
查询时,会先将搜索关键字进行分词,对分词后的字符串进行查询,只要是包含这些字
符串的都是要被查询出来的,多个词之间是 or 的关系。
返回的结果中_score是对这条记录的评分,评分代表这条记录与搜索关键字的匹配度,
查询结果按评分进行降序排序。 比如我们刚才搜索“小米电视” ,那小米电视这条记录的 评分是最高的,排列在最前面。
如果我们需要精确查找,也就是同时包含小米和电视两个词的才可以查询出来,这就需
要将操作改为 and 关系:
代码语言:javascript复制### 精准查询
GET sku/_search
{
"query": {
"match": {
"name": {
"query": "小米电视",
"operator":"and"
}
}
}
}
返回结果:
代码语言:javascript复制{
"took" : 18,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 1.3862944,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dsnu9G4BM_AZ6-65zXIP",
"_score" : 1.3862944,
"_source" : {
"name" : "小米电视",
"price" : 300000,
"spuId" : "105",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "电视",
"saleNum" : 32203,
"commentNum" : 455455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.3.3 多字段查询(multi_match)
代码语言:javascript复制### 多字段查询
GET sku/_search
{
"query":{
"multi_match":{
"query":"小米",
"fields":["name","brandName","categoryName"]
}
}
}
会在name、brandName 、categoryName字段中查询 小米
这个词
2.3.4 词条匹配(term)
term查询被用于精确值 匹配,这些精确值可能是数字、时间、布尔或者那些未分词的字
符串
代码语言:javascript复制###精准查询
GET sku/_search
{
"query":{
"term":{
"price":200000
}
}
}
代码语言:javascript复制查询结果
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 1.0,
"_source" : {
"name" : "三星手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.3.5 多词条匹配(terms)
terms 查询和 term 查询一样,但它允许你指定多值进行匹配。如果这个字段包含了指定 值中的任何一个值,那么这个文档满足条件:
代码语言:javascript复制###精准查询
GET sku/_search
{
"query":{
"terms":{
"price":[100000,200000]
}
}
}
2.3.6 布尔组合(bool)
bool
把各种其它查询通过 must (与)
、must_not (非
)、 should (或
)的方式进行
组合
查询名称包含手机的,并且品牌为小米的。
代码语言:javascript复制#查询名称包含手机的,并且品牌为小米的。
Get sku/_search
{
"query":{
"bool":{
"must":[
{
"match":{
"name":"手机"}},
{
"term":{
"brandName":"小米"}}
]
}
}
}
返回结果
代码语言:javascript复制{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.87546873,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 0.87546873,
"_source" : {
"name" : "三星手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 0.5753642,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
查询名称包含手机的,或者品牌为小米的
代码语言:javascript复制#查询名称包含手机的,并且品牌为小米的。
Get sku/_search
{
"query":{
"bool":{
"should":[
{
"match":{
"name":"手机"}},
{
"term":{
"brandName":"小米"}}
]
}
}
}
2.3.7 过滤查询
过滤是针对搜索的结果进行过滤,过滤器主要判断的是文档是否匹配,不去计算和
判断文档的匹配度得分,所以过滤器性能比查询要高,且方便缓存,推荐尽量使用过滤
器去实现查询或者过滤器和查询共同使用。
代码语言:javascript复制过滤品牌为小米的记录
Get sku/_search
{
"query":{
"bool":{
"filter": [
{
"match":{
"brandName":"小米"}}
]
}
}
}
代码语言:javascript复制结果
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 0.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 0.0,
"_source" : {
"name" : "三星手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dsnu9G4BM_AZ6-65zXIP",
"_score" : 0.0,
"_source" : {
"name" : "小米电视",
"price" : 300000,
"spuId" : "105",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "电视",
"saleNum" : 32203,
"commentNum" : 455455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 0.0,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
}
}
2.3.8 分组查询
按分组名称聚合查询,统计每个分组的数量
代码语言:javascript复制#分组查询
GET sku/_search
{
### aggs 表示分组
"aggs": {
"sku_category": {
//分组展示的名称
"terms": {
"field": "price"
}
}
}
}
代码语言:javascript复制展示结果
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : 1.0,
"hits" : [
{
"_index" : "sku",
"_type" : "doc",
"_id" : "DMnp9G4BM_AZ6-65jnKA",
"_score" : 1.0,
"_source" : {
"name" : "三星手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 55455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dsnu9G4BM_AZ6-65zXIP",
"_score" : 1.0,
"_source" : {
"name" : "小米电视",
"price" : 300000,
"spuId" : "105",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "电视",
"saleNum" : 32203,
"commentNum" : 455455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "Dcnq9G4BM_AZ6-65B3Is",
"_score" : 1.0,
"_source" : {
"name" : "三星电视",
"price" : 400000,
"spuId" : "103",
"createTime" : "2019-05-01",
"brandName" : "三星",
"categerName" : "手机",
"saleNum" : 12203,
"commentNum" : 255455,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "华为手机",
"price" : 400000,
"spuId" : "102",
"createTime" : "2019-05-01",
"brandName" : "华为",
"categerName" : "手机",
"saleNum" : 1403,
"commentNum" : 12656,
"spec" : {
"网络制式" : "全网通",
"屏幕尺寸" : "6.5"
}
}
},
{
"_index" : "sku",
"_type" : "doc",
"_id" : "C8nT9G4BM_AZ6-65IXJW",
"_score" : 1.0,
"_source" : {
"name" : "小米手机",
"price" : 200000,
"spuId" : "101",
"createTime" : "2019-05-01",
"brandName" : "小米",
"categerName" : "手机",
"saleNum" : 1203,
"commentNum" : 2356,
"spec" : {
"网络制式" : "移动4G",
"屏幕尺寸" : "4.5"
}
}
}
]
},
"aggregations" : {
"sku_category" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 200000,
"doc_count" : 2
},
{
"key" : 400000,
"doc_count" : 2
},
{
"key" : 300000,
"doc_count" : 1
}
]
}
}
}
代码语言:javascript复制多个分组查询
GET sku/_search
{
"size": 0, ###如果size:0 表示不用展示hits:[] 里面的数据了
"aggs": {
"sku_category": {
"terms": {
"field": "price"
}
},
"sku_brand": {
"terms": {
"field": "brandName"
}
}
}
}
代码语言:javascript复制{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : 0.0,
"hits" : [ ]
},
"aggregations" : {
"sku_category" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : 200000,
"doc_count" : 2
},
{
"key" : 400000,
"doc_count" : 2
},
{
"key" : 300000,
"doc_count" : 1
}
]
},
"sku_brand" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "小米",
"doc_count" : 3
},
{
"key" : "三星",
"doc_count" : 1
},
{
"key" : "华为",
"doc_count" : 1
}
]
}
}
}
3.使用Java操作索引
3.1 简介
elasticsearch 存在三种Java客户端。
- Transport Client
- Java Low Level Rest Client(低级rest客户端)
- Java High Level REST Client(高级rest客户端)
这三者的区别是:
- TransportClient没有使用RESTful风格的接口,而是二进制的方式传输数据。
- ES官方推出了Java Low Level REST Client,它支持RESTful。但是缺点是因为TransportClient的使用者把代码迁移到Low Level REST Client的工作量比较大。
- ES官方推出Java High Level REST Client,它是基于Java Low Level REST Client的封装,并且API接收参数和返回值和TransportClient是一样的,使得代码迁移变得容易 并且支持了RESTful的风格,兼容了这两种客户端的优点。强烈建议ES5及其以后的版本使用Java High Level REST Client。
准备工作:新建工程,引入依赖
代码语言:javascript复制<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.5.3</version>
</dependency>
3.2 Java操作ElasticSearch中的Index索引
3.2.1 新增和修改数据
插入单条数据:
HttpHost : url地址封装
RestClientBuilder: rest客户端构建器
RestHighLevelClient: rest高级客户端
IndexRequest: 新增或修改请求
IndexResponse:新增或修改的响应结果
代码语言:javascript复制import org.apache.http.HttpHost;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import java.util.HashMap;
import java.util.Map;
public class Demo1 {
public static void main(String[] args) {
//1.链接rest接口
HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
RestClientBuilder restClientBuilder = RestClient.builder(http);
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);
//2.封装请求对象
IndexRequest indexRequest = new IndexRequest("sku", "doc", "3");
Map skuMap = new HashMap();
skuMap.put("name", "华为p30");
skuMap.put("name", "华为p30pro");
skuMap.put("brandName", "华为");
skuMap.put("categoryName", "手机");
skuMap.put("price", 1010221);
skuMap.put("createTime", "2019-05-01");
skuMap.put("saleNum", 101021);
skuMap.put("commentNum", 10102321);
//spec在索引库的类型为Object ,在java代码中我们使用map进行封装spec,然后在封装到外面一层的map。
Map spec = new HashMap();
spec.put("网络制式", "移动4G");
spec.put("屏幕尺寸", "5");
skuMap.put("spec", spec);
indexRequest.source(skuMap);
//3.获取请求结果
try{
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
//执行状态
int status = indexResponse.status().getStatus();
System.out.println(status);
}catch (Exception e){
e.printStackTrace();
}
//关闭资源流
}
}
如果ID不存在则新增,如果ID存在则修改。
批处理请求
批处理请求:
BulkRequest: 批量请求(用于增删改操作)
BulkResponse:批量请求(用于增删改操作)
代码语言:javascript复制import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import java.util.HashMap;
import java.util.Map;
public class Demo2 {
public static void main(String[] args) {
//1.连接rest接口
HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
RestClientBuilder builder = RestClient.builder(http);
//rest构建器
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
//高级客户端对象
// 2.封装请求对象
BulkRequest bulkRequest = new BulkRequest();
IndexRequest indexRequest = new IndexRequest("sku", "doc", "4");
Map skuMap = new HashMap();
skuMap.put("name", "华为p30pro 火爆上市");
skuMap.put("brandName", "华为");
skuMap.put("categoryName", "手机");
skuMap.put("price", 1010221);
skuMap.put("createTime", "2019‐05‐01");
skuMap.put("saleNum", 101021);
skuMap.put("commentNum", 10102321);
Map spec = new HashMap();
spec.put("网络制式", "移动4G");
spec.put("屏幕尺寸", "5");
skuMap.put("spec", spec);
indexRequest.source(skuMap);
bulkRequest.add(indexRequest);
//可以多次添加
// 3.获取响应结果
try {
BulkResponse response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
int status = response.status().getStatus();
System.out.println(status);
String message = response.buildFailureMessage();
System.out.println(message);
restHighLevelClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2.2 匹配查询
SearchRequest: 查询请求对象
SearchResponse:查询响应对象
SearchSourceBuilder:查询源构建器
MatchQueryBuilder:匹配查询构建器
这两个类是构建查询json对象.
代码语言:javascript复制查询商品名称包含手机的记录
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
public class Demo3 {
public static void main(String[] args) throws Exception{
//1.连接rest接口
HttpHost http = new HttpHost("127.0.0.1", 9200, "http");
RestClientBuilder builder = RestClient.builder(http);
RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
//2.封装查询请求
SearchRequest searchRequest = new SearchRequest("sku");
searchRequest.types("doc");//如果不写可以查询所有类型.
//查询源构造器
/* { "query": { ---->new SearchSourceBuilder(); "match": { ----> "name": "手机" ---->MatchQueryBuilder } } } */
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "手机");
searchSourceBuilder.query(matchQueryBuilder);
//相当于最外面的大括号.
searchRequest.source(searchSourceBuilder);
//3.获取查询结果
//相当于 _search
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
SearchHits searchHits = searchResponse.getHits();
long totalHits = searchHits.getTotalHits();
System.out.println("返回记录数:" totalHits);
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String source = hit.getSourceAsString();//json字符串。也可以获取map类型
System.out.println(source);
}
restHighLevelClient.close();
}
}
3.2.3 布尔与词条查询
BoolQueryBuilder:布尔查询构建器
TermQueryBuilder:词条查询构建器
QueryBuilders:查询构建器工厂
代码语言:javascript复制查询名称包含手机的,并且品牌为小米的记录
//1.连接rest接口 同上......
//2.封装查询请求
SearchRequest searchRequest=new SearchRequest("sku");
searchRequest.types("doc");
//设置查询的类型
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//布尔查询构建器
MatchQueryBuilder matchQueryBuilder= QueryBuilders.matchQuery("name","手 机");
boolQueryBuilder.must(matchQueryBuilder);
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米");
boolQueryBuilder.must(termQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
//3.获取查询结果 同上......
3.2.4 过滤查询
代码语言:javascript复制筛选品牌为小米记录
//1.连接rest接口 同上.....
//2.封装查询请求
SearchRequest searchRequest=new SearchRequest("sku");
searchRequest.types("doc");
//设置查询的类型
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//布尔查询构 建器
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brandName", "小米");
boolQueryBuilder.filter(termQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
//3.获取查询结果 同上....
3.2.5 分组(聚合查询)
AggregationBuilders:聚合构建器工厂
TermsAggregationBuilder:词条聚合构建器
Aggregations:分组结果封装
Terms.Bucket: 桶
代码语言:javascript复制按商品分类分组查询,求出每个分类的文档数
//1.连接rest接口
HttpHost http=new HttpHost("127.0.0.1",9200,"http");
RestClientBuilder builder= RestClient.builder(http);
//rest构建器
RestHighLevelClient restHighLevelClient=new RestHighLevelClient(builder);
//高级客户端对象
//2.封装查询请求
SearchRequest searchRequest=new SearchRequest("sku");
searchRequest.types("doc");
//设置查询的类型
SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
TermsAggregationBuilder termsAggregationBuilder =
AggregationBuilders.terms("sku_category").field("categoryName");
searchSourceBuilder.aggregation(termsAggregationBuilder);
searchSourceBuilder.size(0); searchRequest.source(searchSourceBuilder);
//3.获取查询结果
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
Aggregations aggregations = searchResponse.getAggregations();
Map<String, Aggregation> asMap = aggregations.getAsMap();
Terms terms = (Terms) asMap.get("sku_category");
List<? extends Terms.Bucket> buckets = terms.getBuckets();
for(Terms.Bucket bucket:buckets){
System.out.println(bucket.getKeyAsString() ":" bucket.getDocCount());
}
restHighLevelClient.close();
把sku数据批量导入索引库中。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/100762.html原文链接:https://javaforall.cn