原创

ElasticSearch入门文档


ElasticSearch

一、简介

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。ElasticSearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

官方网址:https://www.elastic.co/cn/products/elasticsearch

Github:https://github.com/elastic/elasticsearch

1、elasticsearch是一个基于Lucene的高扩展的分布式搜索服务器,支持开箱即用。

2、elasticsearch隐藏了Lucene的复杂性,对外提供Restful 接口来操作索引、搜索。

3、扩展性好,可部署上百台服务器集群,处理PB级数据。

4、近实时的去索引数据、搜索数据。

二、原理与应用

1、索引结构

索引结构分为逻辑结构和物理结构。

逻辑结构部分是一个倒排索引表:

1、将要搜索的文档内容分词,所有不重复的词组成分词列表。

2、将搜索的文档最终以Document方式存储起来。

3、每个词和docment都有关联。

例子:

Term	Doc_1	Doc_2
----------------------
Quick   |	   |  x  |
The     |	x  |  x  |
brown   |   x  |  x  |
Dog     |	x  |     |
Fox   	|	x  |  x  |
Lazy    |	   |  x  |
quick   |   x  |     |

如果我们想搜索 quick brown ,我们只需要查找包含每个词条的文档:

Term	Doc_1	Doc_2
----------------------
quick   |	x  |     |
brown   |	x  |  x  |

两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配词条数量的简单相似性算法 ,那么,我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳。

2、使用方法

Elasticsearch提供 RESTful Api接口进行索引、搜索,并且支持多种客户端。

如何在项目中使用?

1)用户在前端搜索关键字

2)项目前端通过http方式请求项目服务端 ,项目服务端可定制搜索

3)项目服务端通过Http RESTful方式请求ES集群进行搜索

4)ES集群从索引库检索数据。

三、安装

1、安装配置

1、新版本要求至少jdk1.8以上。

2、支持tar、zip、rpm等多种安装方式,在windows下开发建议使用ZIP安装方式。

3、支持docker方式安装 详细参见:https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html

解压 elasticsearch-6.2.1.zip

bin:脚本目录,包括:启动、停止等可执行脚本

config:配置文件目录

data:索引目录,存放索引文件的地方

logs:日志目录

modules:模块目录,包括了es的功能模块

plugins:插件目录,es支持插件机制

2、配置文件

ES的配置文件的地址根据安装形式的不同而不同:

使用zip、tar安装,配置文件的地址在安装目录的confifig下。

使用RPM安装,配置文件在/etc/elasticsearch下。

使用MSI安装,配置文件的地址在安装目录的confifig下,并且会自动将confifig目录地址写入环境变量 ES_PATH_CONF。

配置文件如下:

elasticsearch.yml:用于配置Elasticsearch运行参数

jvm.options::用于配置ElasticSearch JVM设置

log4j2.properties:用于配置ElasticSearch日志

3、配置文件详解

1)elasticsearch.yml

配置格式是YAML,可以采用如下两种方式:

方式1:层次方式

path:
	data: /var/lib/elasticsearch
	logs: /var/log/elasticsearch

方式2:属性方式

path.data: /var/lib/elasticsearch 
path.logs: /var/log/elasticsearch

配置例子:

cluster.name: xuecheng
node.name: xc_node_1
network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
node.master: true
node.data: true 
#discovery.zen.ping.unicast.hosts: ["0.0.0.0:9300", "0.0.0.0:9301", "0.0.0.0:9302"]
discovery.zen.minimum_master_nodes: 1
bootstrap.memory_lock: false
node.max_local_storage_nodes: 1
#注意path.data和path.logs路径配置正确。
path.data: D:\ElasticSearch\elasticsearch‐6.2.1\data 
path.logs: D:\ElasticSearch\elasticsearch‐6.2.1\logs 
http.cors.enabled: true 
http.cors.allow‐origin: /.*/

常用的配置项如下:

cluster.name:配置elasticsearch的集群名称,默认是elasticsearch。建议修改成一个有意义的名称。

node.name:节点名,通常一台物理服务器就是一个节点,es会默认随机指定一个名字,建议指定一个有意义的名称,方便管理。一个或多个节点组成一个cluster集群,集群是一个逻辑的概念,节点是物理概念。

path.conf:设置配置文件的存储路径,tar或zip包安装默认在es根目录下的confifig文件夹,rpm安装默认在/etc/elasticsearch

path.data:设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,用逗号隔开。 path.logs:设置日志文件的存储路径,默认是es根目录下的logs文件夹

path.plugins:设置插件的存放路径,默认是es根目录下的plugins文件夹

bootstrap.memory_lock: true 设置为true可以锁住ES使用的内存,避免内存与swap分区交换数据。

network.host:设置绑定主机的ip地址,设置为0.0.0.0表示绑定任何ip,允许外网访问,生产环境建议设置为具体 的ip。

http.port:设置对外服务的http端口,默认为9200。

transport.tcp.port:集群结点之间通信端口

node.master:指定该节点是否有资格被选举成为master结点,默认是true,如果原来的master宕机会重新选举新 的master。

node.data:指定该节点是否存储索引数据,默认为true。

discovery.zen.ping.unicast.hosts: ["host1:port", "host2:port", "..."] :设置集群中master节点的初始列表。

discovery.zen.ping.timeout: 3s :设置ES自动发现节点连接超时的时间,默认为3秒,如果网络延迟高可设置大些。

discovery.zen.minimum_master_nodes:主结点数量的最少值 ,此值的公式为:(master_eligible_nodes / 2) + 1 ,比如:有3个符合要求的主结点,那么这里要设置为2。

node.max_local_storage_nodes:单机允许的最大存储结点数,通常单机启动一个结点建议设置为1,开发环境如果单机启动多个节点可设置大于1.

2)jvm.options

设置最小及最大的JVM堆内存大小:

在jvm.options中设置 -Xms和-Xmx:

1) 两个值设置为相等

2) 将 Xmx 设置为不超过物理内存的一半

3)log4j2.properties

日志文件设置,ES使用log4j,注意日志级别的配置。

4、系统配置

在linux上根据系统资源情况,可将每个进程最多允许打开的文件数设置大些。

su limit -n 查询当前文件数

使用命令设置limit:

先切换到root,设置完成再切回elasticsearch用户。

sudo su
ulimit ‐n 65536
su elasticsearch

也可通过下边的方式修改文件进行持久设置

/etc/security/limits.conf 将下边的行加入此文件:

elasticsearch ‐ nofile 65536

5、启动ES

在windows环境下,进入安装的bin目录下,直接运行脚本elasticsearch.bat,浏览器输入:http://localhost:9200 ,如果出现以下内容,则证明启动成功:

{
  "name" : "xc_node_1",
  "cluster_name" : "xuecheng",
  "cluster_uuid" : "z9Vb5SIjRySnO6TmKLT1zw",
  "version" : {
    "number" : "6.2.1",
    "build_hash" : "7299dc3",
    "build_date" : "2018-02-07T19:34:26.990113Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

6、head插件安装

head插件是ES的一个可视化管理插件,用来监视ES的状态,并通过head客户端和ES服务进行交互,比如创建映 射、创建索引等,head的项目地址在https://github.com/mobz/elasticsearch-head

从ES6.0开始,head插件支持使得node.js运行。

1、安装node.js

2、下载head并运行

git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start 

访问:http://localhost:9100/

打开浏览器调试工具发现报错:Origin null is not allowed by Access-Control-Allow-Origin.

原因是:head插件作为客户端要连接ES服务(localhost:9200),此时存在跨域问题,elasticsearch默认不允许跨域访问。

解决方案:设置elasticsearch允许跨域访问。

在config/elasticsearch.yml 后面增加以下参数:

#开启cors跨域访问支持,默认为false
http.cors.enabled: true 
#跨域访问允许的域名地址,(允许所有域名)以上使用正则
http.cors.allow-origin: /.*/ 

注意:将config/elasticsearch.yml另存为utf-8编码格式。

四、ES快速入门

1、创建索引库

ES的索引库是一个逻辑概念,它包括了分词列表及文档列表,同一个索引库中存储了相同类型的文档。它就相当于MySQL中的表,或相当于Mongodb中的集合。

关于索引这个语:

索引(名词):ES是基于Lucene构建的一个搜索服务,它要从索引库搜索符合条件索引数据。

索引(动词):索引库刚创建起来是空的,将数据添加到索引库的过程称为索引。

下边介绍两种创建索引库的方法,它们的工作原理是相同的,都是客户端向ES服务发送命令。

1)使用postman或curl这样的工具创建: 使用put发送请求http://localhost:9200/索引库名称

//发送json数据
{
	"settings": {
		"index": {
            // 分片数量
			"number_of_shards": 1,
            // 副本数量
			"number_of_replicas":0
		}
	}
}

响应数据:

{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "xc_course"
}

number_of_shards:设置分片的数量,在集群中通常设置多个分片,表示一个索引库将拆分成多片分别存储不同 的结点,提高了ES的处理能力和高可用性,入门程序使用单机环境,这里设置为1。

number_of_replicas:设置副本的数量,设置副本是为了提高ES的高可靠性,单机环境设置为0。

2、创建映射

1)概念说明:

在索引中每个文档都包括了一个或多个field,创建映射就是向索引库中创建field的过程,下边是document和field与关系数据库的概念的类比:文档(Document)--------Row记录;字段(Field)----------Columns 列

注意:6.0之前的版本有type(类型)概念,type相当于关系数据库的表,ES官方将在ES9.0版本中彻底删除type。

上边讲的创建索引库相当于关系数据库中的数据库还是表?

1、如果相当于数据库就表示一个索引库可以创建很多不同类型的文档,这在ES中也是允许的。

2、如果相当于表就表示一个索引库只能存储相同类型的文档,ES官方建议在一个索引库中只存储相同类型的文

档。

2)创建映射

发送post请求:http://localhost:9200/索引库名称/类型名称/_mapping

由于ES6.0版本还没有将type彻底删除,所以暂时把type起一个没有特殊意义的名字。

// 使用Postman发送Post请求:http://localhost:9200/xc_course/doc/_mapping
// 发送的数据为:
{
	"properties": {
		"name": {
			"type": "text"
		},
		"description": {
			"type": "text"
		},
		"studymodel": {
			"type": "keyword"
		}
	}
}

注意:在xc_course索引库下的doc类型下创建映射。doc是类型名,可以自定义,在ES6.0中要弱化类型的概念,

给它起一个没有具体业务意义的名称。

// 接收到的数据为:
{
    "acknowledged": true
}

可使用Postman发送Get请求到同一地址,查询映射信息:

// 使用Postman发送Get请求:http://localhost:9200/xc_course/doc/_mapping
// 响应的数据格式为:
{
    "xc_course": {
        "mappings": {
            "doc": {
                "properties": {
                    "description": {
                        "type": "text"
                    },
                    "name": {
                        "type": "text"
                    },
                    "studymodel": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

3、创建文档

ES中的文档相当于MySQL数据库表中的记录。发送Put或Post请求:http://localhost:9200/xc_course/doc/id值 (如果不指定id值ES会自动生成ID)

// 使用Postman发送Put或Post请求:http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0000
// 请求的数据为:
{
    "name":"Bootstrap开发框架",
    "description":"Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
    "studymodel":"201001"
}
// 响应的数据为:
{
    "_index": "xc_course",
    "_type": "doc",
    "_id": "4028e58161bcf7f40161bcf8b77c0000",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}

4、搜索文档

1、根据课程id查询文档

// 发送Get请求:http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0000
// 响应的数据格式为:
{
    "_index": "xc_course",
    "_type": "doc",
    "_id": "4028e58161bcf7f40161bcf8b77c0000",
    "_version": 1,
    "found": true,
    "_source": {
        "name": "Bootstrap开发框架",
        "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
        "studymodel": "201001"
    }
}

2、查询所有记录

// 发送Get请求:http://localhost:9200/xc_course/doc/_search
// 响应的数据格式为:
{
    "took": 110,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 1.0,
        "hits": [
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "4028e58161bcf7f40161bcf8b77c0000",
                "_score": 1.0,
                "_source": {
                    "name": "Bootstrap开发框架",
                    "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
                    "studymodel": "201001"
                }
            }
        ]
    }
}

took:本次操作花费的时间,单位为毫秒。

timed_out:请求是否超时

_shards:说明本次操作共搜索了哪些分片

hits:搜索命中的记录

hits.total : 符合条件的文档总数 hits.hits :匹配度较高的前N个文档

hits.max_score:文档匹配得分,这里为最高分

_score:每个文档都有一个匹配度得分,按照降序排列。

_source:显示了文档的原始内容。

3、查询名称中包括bootstrap关键字的的记录

发送Get请求:http://localhost:9200/xc_course/doc/_search?q=name:bootstrap

4、查询学习模式为201001的记录

发送Get请求:http://localhost:9200/xc_course/doc/_search?q=studymodel:201001

5、删除文档:根据课程id使用Delete请求删除文档

http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0001

// 响应的数据为:
{
    "_index": "xc_course",
    "_type": "doc",
    "_id": "4028e58161bcf7f40161bcf8b77c0001",
    "_version": 2,
    "result": "deleted",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
}

5、更新文档

ES更新文档的顺序是:先检索到文档、将原来的文档标记为删除、创建新文档、删除旧文档,创建新文档就会重建索引。

通过请求Url有两种方法:

1、完全替换:Post请求:http://localhost:9200/xc_test/doc/3

// 请求的数据为:
{
    "name": "spring cloud实战",
    "description": "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud 基础入门。",
    "studymodel": "201001",
    "price": 5.6
}
// 响应的数据为:
{
    "_index": "xc_test",
    "_type": "doc",
    "_id": "3",
    "_version": 2,
    "result": "updated",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 1,
    "_primary_term": 1
}

2、局部更新:下边的例子是只更新price字段,Post请求:http://localhost:9200/xc_test/doc/3/_update

// 请求的数据为:
{ "doc":{"price":66.6} }
// 响应的数据为:
{
    "_index": "xc_test",
    "_type": "doc",
    "_id": "3",
    "_version": 3,
    "result": "updated",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 2,
    "_primary_term": 1
}
// Get请求:http://localhost:9200/xc_test/doc/3,可查询到price字段的值已更新

6、删除文档

1、根据id删除,格式如下:Delete请求:http://localhost:9200/{index}/{type}/{id}

2、搜索匹配删除,将搜索出来的记录删除,格式如下:Post请求:http://localhost:9200/{index}/{type}/_delete_by_query

// 搜索条件的数据为:
{
    "query": {
        "term": {
            "studymodel": "201001"
        }
    }
}
// 响应的数据为:
{
    "took": 57,
    "timed_out": false,
    "total": 1,
    "deleted": 1,
    "batches": 1,
    "version_conflicts": 0,
    "noops": 0,
    "retries": {
        "bulk": 0,
        "search": 0
    },
    "throttled_millis": 0,
    "requests_per_second": -1.0,
    "throttled_until_millis": 0,
    "failures": []
}

五、IK分词器

1、测试默认分词器

在添加文档时会进行分词,索引中存放的就是一个一个的词(term),当你去搜索时就是拿关键字去匹配词,最终找到词关联的文档。

测试当前索引库使用的分词器:

// 发送Post请求:http://localhost:9200/_analyze
// 发送的数据为:
{
    "text":"测试分词器,后边是测试内容:spring cloud实战"
}
// 响应的数据为:
{
    "tokens": [
        {
            "token": "测",
            "start_offset": 0,
            "end_offset": 1,
            "type": "<IDEOGRAPHIC>",
            "position": 0
        },
        {
            "token": "试",
            "start_offset": 1,
            "end_offset": 2,
            "type": "<IDEOGRAPHIC>",
            "position": 1
        },
        {
            "token": "分",
            "start_offset": 2,
            "end_offset": 3,
            "type": "<IDEOGRAPHIC>",
            "position": 2
        },
        {
            "token": "词",
            "start_offset": 3,
            "end_offset": 4,
            "type": "<IDEOGRAPHIC>",
            "position": 3
        },
        {
            "token": "器",
            "start_offset": 4,
            "end_offset": 5,
            "type": "<IDEOGRAPHIC>",
            "position": 4
        },
        {
            "token": "后",
            "start_offset": 6,
            "end_offset": 7,
            "type": "<IDEOGRAPHIC>",
            "position": 5
        },
        {
            "token": "边",
            "start_offset": 7,
            "end_offset": 8,
            "type": "<IDEOGRAPHIC>",
            "position": 6
        },
        {
            "token": "是",
            "start_offset": 8,
            "end_offset": 9,
            "type": "<IDEOGRAPHIC>",
            "position": 7
        },
        {
            "token": "测",
            "start_offset": 9,
            "end_offset": 10,
            "type": "<IDEOGRAPHIC>",
            "position": 8
        },
        {
            "token": "试",
            "start_offset": 10,
            "end_offset": 11,
            "type": "<IDEOGRAPHIC>",
            "position": 9
        },
        {
            "token": "内",
            "start_offset": 11,
            "end_offset": 12,
            "type": "<IDEOGRAPHIC>",
            "position": 10
        },
        {
            "token": "容",
            "start_offset": 12,
            "end_offset": 13,
            "type": "<IDEOGRAPHIC>",
            "position": 11
        },
        {
            "token": "spring",
            "start_offset": 14,
            "end_offset": 20,
            "type": "<ALPHANUM>",
            "position": 12
        },
        {
            "token": "cloud",
            "start_offset": 21,
            "end_offset": 26,
            "type": "<ALPHANUM>",
            "position": 13
        },
        {
            "token": "实",
            "start_offset": 26,
            "end_offset": 27,
            "type": "<IDEOGRAPHIC>",
            "position": 14
        },
        {
            "token": "战",
            "start_offset": 27,
            "end_offset": 28,
            "type": "<IDEOGRAPHIC>",
            "position": 15
        }
    ]
}

会发现分词的效果将 "测试" 这个词拆分成两个单字"测"和"试",这是因为当前索引库使用的分词器对中文就是单字

分词。

2、安装IK分词器

使用IK分词器可以实现对中文分词的效果。

下载IK分词器:(Github地址:https://github.com/medcl/elasticsearch-analysis-ik) 找到对应的版本

解压,并将解压的文件拷贝到ES安装目录的plugins下的ik目录下,并重启ES

// 发送Post请求:http://localhost:9200/_analyze
// 发送的数据为:
{
    "text":"测试分词器,后边是测试内容:spring cloud实战",
    "analyzer":"ik_max_word"
}
// 响应的数据为:
{
    "tokens": [
        {
            "token": "测试",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "分词器",
            "start_offset": 2,
            "end_offset": 5,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "分词",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "器",
            "start_offset": 4,
            "end_offset": 5,
            "type": "CN_CHAR",
            "position": 3
        },
        {
            "token": "后边",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 4
        },
        {
            "token": "是",
            "start_offset": 8,
            "end_offset": 9,
            "type": "CN_CHAR",
            "position": 5
        },
        {
            "token": "测试",
            "start_offset": 9,
            "end_offset": 11,
            "type": "CN_WORD",
            "position": 6
        },
        {
            "token": "内容",
            "start_offset": 11,
            "end_offset": 13,
            "type": "CN_WORD",
            "position": 7
        },
        {
            "token": "spring",
            "start_offset": 14,
            "end_offset": 20,
            "type": "ENGLISH",
            "position": 8
        },
        {
            "token": "cloud",
            "start_offset": 21,
            "end_offset": 26,
            "type": "ENGLISH",
            "position": 9
        },
        {
            "token": "实战",
            "start_offset": 26,
            "end_offset": 28,
            "type": "CN_WORD",
            "position": 10
        }
    ]
}

3、两种分词模式

IK分词器有两种分词模式:ik_max_word和ik_smart模式。

1、ik_max_word:会将文本做最细粒度的拆分,比如会将"中华人民共和国人民大会堂"拆分为"中华人民共和国、中华人民、中华、华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。

2、ik_smart:会做最粗粒度的拆分,比如会将"中华人民共和国人民大会堂"拆分为中华人民共和国、人民大会堂。

// 测试两种分词模式
// ik_max_word模式
// 发送Post请求:http://localhost:9200/_analyze
// 发送的数据为:
{
    "text":"中华人民共和国人民大会堂",
    "analyzer":"ik_max_word"
}
// 响应的数据为:
{
    "tokens": [
        {
            "token": "中华人民共和国",
            "start_offset": 0,
            "end_offset": 7,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "中华人民",
            "start_offset": 0,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "中华",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "华人",
            "start_offset": 1,
            "end_offset": 3,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "人民共和国",
            "start_offset": 2,
            "end_offset": 7,
            "type": "CN_WORD",
            "position": 4
        },
        {
            "token": "人民",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 5
        },
        {
            "token": "共和国",
            "start_offset": 4,
            "end_offset": 7,
            "type": "CN_WORD",
            "position": 6
        },
        {
            "token": "共和",
            "start_offset": 4,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 7
        },
        {
            "token": "国人",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 8
        },
        {
            "token": "人民大会堂",
            "start_offset": 7,
            "end_offset": 12,
            "type": "CN_WORD",
            "position": 9
        },
        {
            "token": "人民大会",
            "start_offset": 7,
            "end_offset": 11,
            "type": "CN_WORD",
            "position": 10
        },
        {
            "token": "人民",
            "start_offset": 7,
            "end_offset": 9,
            "type": "CN_WORD",
            "position": 11
        },
        {
            "token": "大会堂",
            "start_offset": 9,
            "end_offset": 12,
            "type": "CN_WORD",
            "position": 12
        },
        {
            "token": "大会",
            "start_offset": 9,
            "end_offset": 11,
            "type": "CN_WORD",
            "position": 13
        },
        {
            "token": "会堂",
            "start_offset": 10,
            "end_offset": 12,
            "type": "CN_WORD",
            "position": 14
        }
    ]
}

// ik_smart模式
// 发送Post请求:http://localhost:9200/_analyze
// 发送的数据为:
{
    "text":"中华人民共和国人民大会堂",
    "analyzer":"ik_smart"
}
// 响应的数据为:
{
    "tokens": [
        {
            "token": "中华人民共和国",
            "start_offset": 0,
            "end_offset": 7,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "人民大会堂",
            "start_offset": 7,
            "end_offset": 12,
            "type": "CN_WORD",
            "position": 1
        }
    ]
}

4、自定义词库

如果要让分词器支持一些专有词语,可以自定义词库。IK分词器自带一个main.dic的文件,此文件为词库文件。

在上边的目录中新建一个my.dic文件(注意文件格式为utf-8)可按照main.dic的格式自定义词汇,并在IKAnalyzer.cfg.xml文件中配置my.dic文件,重启ES。

// my.dic文件内容
李哲龙
海贼王
// IKAnalyzer.cfg.xml配置文件内容
<?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>

可看见原来把 李哲龙 拆分成三个词的,现在合并成为一个词了。

// 发送Post请求:http://localhost:9200/_analyze
// 发送的数据为:
{
    "text":"李哲龙",
    "analyzer":"ik_max_word"
}
// 响应的数据为:
{
    "tokens": [
        {
            "token": "李哲龙",
            "start_offset": 0,
            "end_offset": 3,
            "type": "CN_WORD",
            "position": 0
        }
    ]
}

六、映射

1、映射维护方法

1、查询所有索引的映射:发送Get请求:http://localhost:9200/_mapping

// 返回的数据为:
{
    "xc_course": {
        "mappings": {
            "doc": {
                "properties": {
                    "description": {
                        "type": "text"
                    },
                    "name": {
                        "type": "text"
                    },
                    "studymodel": {
                        "type": "keyword"
                    }
                }
            }
        }
    }
}

2、创建映射:发送Post请求:http://localhost:9200/xc_course/doc/_mapping

// 请求的数据为:
{
    "properties":{
        "name":{
            "type":"text"
        },
        "description":{
            "type":"text"
        },
        "studymodel":{
            "type":"keyword"
        }
    }
}
// 返回的数据为:
{
    "acknowledged": true
}

3、更新映射:映射创建成功可以添加新字段,已有字段的类型不允许更新。除非把整个索引库全部删除,重建。

// 如果把description的字段类型从keyword变为text,不会成功
// 已有字段的类型修改时,会报错误的信息为:
{
    "error": {
        "root_cause": [
            {
                "type": "illegal_argument_exception",
                "reason": "mapper [studymodel] of different type, current_type [text], merged_type [keyword]"
            }
        ],
        "type": "illegal_argument_exception",
        "reason": "mapper [studymodel] of different type, current_type [text], merged_type [keyword]"
    },
    "status": 400
}

4、删除映射:通过删除索引来删除映射,发送Delete请求:http://localhost:9200/xc_course

2、常用映射类型

字符串类型有text和keyword类型;日期有date类型;数值有long,integer,short,float,byte,double,half_float,scaled_float;

1、text文本字段

1)analyzer:通过analyzer属性指定分词器。

下边指定name的字段类型为text,使用IK分词器的ik_max_word分词模式。

{
    "name": {
        "type": "text",
        "analyzer": "ik_max_word"
    }
}

上边指定了analyzer是指在索引和搜索都使用ik_max_word,如果单独想定义搜索时使用的分词器则可以通过search_analyzer属性。对于IK分词器建议是索引时使用ik_max_word将搜索内容进行细粒度分词,搜索时使用ik_smart提高搜索精确性。

{
    "name": {
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
    }
}

2)index:通过index属性指定是否索引。

默认为index=true,即要进行索引,只有进行索引才可以从索引库搜索到。但是也有一些内容不需要索引,比如:商品图片地址只被用来展示图片,不进行搜索图片,此时可以将index设置为false。

// 删除索引,重新创建映射,将pic的index设置为false,尝试根据pic去搜索,结果搜索不到数据
{
    "pic": {
        "type": "text",
        "index": false
    }
}

3)store:是否在source之外存储。每个文档索引后会在 ES中保存一份原始文档,存放_source在中,一般情况下不需要设置store为true,因为在_source中已经有一份原始文档了。

4)完整的例子:

删除xc_course索引库:Delete:http://localhost:9200/xc_course

// 响应的数据为:
{
    "acknowledged": true
}

创建新的xc_course索引库:Put:http://localhost:9200/xc_course

// 设置的数据为:
{
	"settings": {
		"index": {
			"number_of_shards": 1,
			"number_of_replicas":0
		}
	}
}
// 响应的数据为:
{
    "acknowledged": true,
    "shards_acknowledged": true,
    "index": "xc_course"
}

创建新映射:Post或Put:http://localhost:9200/xc_course/doc/_mapping

// 创建映射添加的数据为:
{
    "properties":{
        "name":{
            "type":"text",
            "analyzer":"ik_max_word",
            "search_analyzer":"ik_smart"
        },
        "description":{
            "type":"text",
            "analyzer":"ik_max_word",
            "search_analyzer":"ik_smart"
        },
        "pic":{
            "type":"text",
            "index":false
        },
        "studymodel":{
            "type":"text"
        }
    }
}
// 响应的数据为:
{
    "acknowledged": true
}

插入文档:Post或Put:http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0000

// 插入的文档数据为:
{
    "name": "Bootstrap开发框架",
    "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
    "studymodel": "201002"
}
// 响应的数据为:
{
    "_index": "xc_course",
    "_type": "doc",
    "_id": "4028e58161bcf7f40161bcf8b77c0000",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}

查询测试:

Get http://localhost:9200/xc_course/_search?q=name:开发

{
    "took": 35,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.2876821,
        "hits": [
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "4028e58161bcf7f40161bcf8b77c0000",
                "_score": 0.2876821,
                "_source": {
                    "name": "Bootstrap开发框架",
                    "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
                    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
                    "studymodel": "201002"
                }
            }
        ]
    }
}

Get http://localhost:9200/xc_course/_search?q=description:开发

{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.48957998,
        "hits": [
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "4028e58161bcf7f40161bcf8b77c0000",
                "_score": 0.48957998,
                "_source": {
                    "name": "Bootstrap开发框架",
                    "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
                    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
                    "studymodel": "201002"
                }
            }
        ]
    }
}

Get http://localhost:9200/xc_course/_search?q=pic:group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg

// 由于pic的index为false,所以不能搜索到数据
{
    "took": 5,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 0,
        "max_score": null,
        "hits": []
    }
}

Get http://localhost:9200/xc_course/_search?q=studymodel:201002

{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.2876821,
        "hits": [
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "4028e58161bcf7f40161bcf8b77c0000",
                "_score": 0.2876821,
                "_source": {
                    "name": "Bootstrap开发框架",
                    "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
                    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
                    "studymodel": "201002"
                }
            }
        ]
    }
}

通过测试发现:name和description都支持全文检索,pic不可作为查询条件。

2、keyword关键字字段

上边介绍的text文本字段在映射时要设置分词器,keyword字段为关键字字段,通常搜索keyword是按照整体搜索,所以创建keyword字段的索引时是不进行分词的,比如:邮政编码、手机号码、身份证等。keyword字段通常用于过虑、排序、聚合等。

测试:

更改映射,Put/Post请求:http://localhost:9200/xc_course/doc/_mapping

// 发送的数据为:
{
    "properties": {
    	"name": {
            "type": "keyword"
        },
        "description": {
            "type": "text",
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_smart"
        },
        "pic": {
            "type": "text",
            "index": false
        },
        "studymodel": {
            "type": "keyword"
        }
        
    }
}
// 返回的数据为:
{
    "acknowledged": true
}

插入文档:Post/Put请求:http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0000

// 请求的数据为:
{
    "name": "Bootstrap开发框架",
    "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包 含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。",
    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
    "studymodel": "201002"
}
// 返回的数据为:
{
    "_index": "xc_course",
    "_type": "doc",
    "_id": "4028e58161bcf7f40161bcf8b77c0000",
    "_version": 1,
    "result": "created",
    "_shards": {
        "total": 1,
        "successful": 1,
        "failed": 0
    },
    "_seq_no": 0,
    "_primary_term": 1
}

根据studymodel查询文档,搜索:Get:http://localhost:9200/xc_course/_search?q=name:java

// 返回的数据为:
{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 0,
        "max_score": null,
        "hits": []
    }
}

name是keyword类型,所以查询方式是精确查询。

3、date日期类型

日期类型不用设置分词器。通常日期类型的字段用于排序。format:通过format设置日期格式

下边的设置允许date字段存储年月日时分秒、年月日及毫秒三种格式。

// 在插入索引的时候:指定日期类型
// Put/Post请求:http://localhost:9200/xc_course/doc/_mapping
{
    "properties": {
        "name": {
            "type": "keyword"
        },
        "description": {
            "type": "text",
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_smart"
        },
        "pic": {
            "type": "text",
            "index": false
        },
        "studymodel": {
            "type": "keyword"
        },
        "timestamp": {
            "type": "date",
            "format": "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd||epoch_millis"
        }
    }
}
// 插入文档:Post/Put请求:http://localhost:9200/xc_course/doc/3
{
    "name": "spring开发基础",
    "description": "spring 在java领域非常流行,java程序员都在用。",
    "studymodel": "201001",
    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
    "timestamp": "2018‐07‐04 18:28:58"
}

4、数值类型

ES支持的数据类型为:long,integer,short,float,byte,double,half_float,scaled_float;

选择数据类型的建议:

1、尽量选择范围小的类型,提高搜索效率

2、对于浮点数尽量用比例因子,比如一个价格字段,单位为元,我们将比例因子设置为100这在ES中会按分存 储,映射如下:

"price": { "type": "scaled_float", "scaling_factor": 100 }

由于比例因子为100,如果我们输入的价格是23.45则ES中会将23.45乘以100存储在ES中。如果输入的价格是23.456,ES会将23.456乘以100再取一个接近原始值的数,得出2346。使用比例因子的好处是整型比浮点型更易压缩,节省磁盘空间。

3、如果比例因子不适合,则从下表选择范围小的去用:

TypeMinimum valueMaximum valueSignificant bits / digits
double2^-1074(2-2^-52)*2^102353 / 15.95
float2^-149(2-2^-23)*2^12724 / 7.22
half_float2^-246550411 / 3.31

4、测试例子:

// 更新已有映射,Post请求:localhost:9200/xc_course/doc/_mapping,发送的数据为:
{
    "properties": {
        "name": {
            "type": "keyword"
        },
        "description": {
            "type": "text",
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_smart"
        },
        "pic": {
            "type": "text",
            "index": false
        },
        "studymodel": {
            "type": "keyword"
        },
        "timestamp": {
            "type": "date",
            "format": "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd"
        },
        "price": {
            "type": "scaled_float",
            "scaling_factor": 100
        }
    }
}
// 并插入文档:Post请求:http://localhost:9200/xc_course/doc/3,发送的数据为:
{
    "name": "spring开发基础",
    "description": "spring 在java领域非常流行,java程序员都在用。",
    "studymodel": "201001",
    "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
    "timestamp": "2018‐07‐04 18:28:58",
    "price": 38.6
}
// 查询文档数据:Get请求:http://localhost:9200/xc_course/doc/3,返回的数据为:
{
    "_index": "xc_course",
    "_type": "doc",
    "_id": "3",
    "_version": 2,
    "found": true,
    "_source": {
        "name": "spring开发基础",
        "description": "spring 在java领域非常流行,java程序员都在用。",
        "studymodel": "201001",
        "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
        "timestamp": "2018‐07‐04 18:28:58",
        "price": 38.6
    }
}

3、综合测试例子

创建如下映射:Post:http://localhost:9200/xc_course/doc/_mapping

{
    "properties": {
        "description": {
            "type": "text",
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_smart"
        },
        "name": {
            "type": "text",
            "analyzer": "ik_max_word",
            "search_analyzer": "ik_smart"
        },
        "pic": {
            "type": "text",
            "index": false
        },
        "price": {
            "type": "float"
        },
        "studymodel": {
            "type": "keyword"
        },
        "timestamp": {
            "type": "date",
            "format": "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd||epoch_millis"
        }
    }
}

插入文档:Post请求:http://localhost:9200/xc_course/doc/1

{
    "name": "Bootstrap开发",
    "description": "Bootstrap是由Twitter 推出的一个前台页面开发框架,是一个非常流行的开发框架,此框架集成了多种页面效果。此开发框架包含了大量 的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的精 美界面效果。",
    "studymodel": "201002",
    "price": 38.6,
    "timestamp": "2018-04-25 19:11:35",
    "pic": "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg"
}

七、DSL搜索

DSL(Domain Specifific Language)是ES提出的基于json的搜索方式,在搜索时传入特定的json格式的数据来完成不同的搜索需求。DSL比URI搜索方式功能强大,在项目中建议使用DSL方式来完成搜索。

1、查询所有文档

查询所有索引库的文档: 发送Post请求:http://localhost:9200/_search

查询指定索引库指定类型下的文档:

发送Post请求:http://localhost:9200/xc_course/doc/_search

// 请求的数据为:
{
    "query": {
        "match_all": {}
    },
    "_source": [
        "name",
        "studymodel"
    ]
}
// 返回的数据为:
{
    "took": 8,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 3,
        "max_score": 1.0,
        "hits": [
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "studymodel": "201002",
                    "name": "Bootstrap开发"
                }
            },
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "studymodel": "201001",
                    "name": "java编程基础"
                }
            },
            {
                "_index": "xc_course",
                "_type": "doc",
                "_id": "3",
                "_score": 1.0,
                "_source": {
                    "studymodel": "201001",
                    "name": "spring开发基础"
                }
            }
        ]
    }
}

_source:source源过虑设置,指定结果中所包括的字段有哪些。

结果说明:

took:本次操作花费的时间,单位为毫秒。

timed_out:请求是否超时

_shards:说明本次操作共搜索了哪些分片

hits:搜索命中的记录

hits.total : 符合条件的文档总数

hits.hits :匹配度较高的前N个文档

hits.max_score:文档匹配得分,这里为最高分

_score:每个文档都有一个匹配度得分,按照降序排列。

_source:显示了文档的原始内容。

2、分页查询

ES支持分页查询,传入两个参数:from和size。

from:表示起始文档的下标,从0开始。size:查询的文档数量。

发送Post请求:http://localhost:9200/xc_course/doc/_search

// 请求的数据为:
{
    "from": 0,
    "size": 1,
    "query": {
        "match_all": {}
    },
    "_source": [
        "name",
        "studymodel"
    ]
}

3、Term Query

Term Query为精确查询,在搜索时会整体匹配关键字,不再将关键字分词。

发送Post请求:http://localhost:9200/xc_course/doc/_search

// 请求的数据为:
{
    "query": {
        "term": {
            "name": "spring开发"
        }
    },
    "_source": [
        "name",
        "studymodel"
    ]
}
// 不会将name进行分词,所以name中必须全部包含spring开发的才能被搜索到

4、根据Id精确匹配

ES提供根据多个id值匹配的方法:

发送Post请求:http://127.0.0.1:9200/xc_course/doc/_search

// 请求的数据为:
{
    "query": {
        "ids": {
            "type": "doc",
            "values": [
                "3",
                "4",
                "100"
            ]
        }
    }
}

5、Match Query

1、基本使用

Match Query即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。

Match query与Term query区别是Match Query在搜索前先将搜索关键字分词,再拿各各词语去索引中搜索。

发送Post请求:http://localhost:9200/xc_course/doc/_search

// 请求的数据为:
{
    "query": {
        "match": {
            "description": {
                "query": "spring开发",
                "operator": "or"
            }
        }
    }
}

query:搜索的关键字,对于英文关键字如果有多个单词则中间要用半角逗号分隔,而对于中文关键字中间可以用 逗号分隔也可以不用。

operator:or表示:只要有一个词在文档中出现则就符合条件,and表示:每个词都在文档中出现则才符合条件。

上边的搜索的执行过程是:

1)将"spring开发"分词,分为spring、开发两个词

2)再使用spring和开发两个词去匹配索引中搜索。

3)由于设置了operator为or,只要有一个词匹配成功则就返回该文档。

2、minimum_should_match

上边使用的operator = or表示只要有一个词匹配上就得分,如果实现三个词至少有两个词匹配如何实现?

使用minimum_should_match可以指定文档匹配词的占比:

比如搜索语句如下:

{
    "query": {
        "match": {
            "description": {
                "query": "spring开发框架",
                "minimum_should_match": "80%"
            }
        }
    }
}

"spring开发框架"会被分为三个词:spring、开发、框架

设置"minimum_should_match": "80%"表示,三个词在文档的匹配占比为80%,即3*0.8=2.4,向上取整得2,表 示至少有两个词在文档中要匹配成功。

6、Multi Query

上边学习的termQuery和matchQuery一次只能匹配一个Field,本节学习multiQuery,一次可以匹配多个字段。

1、基本使用

单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配。

发送Post请求:http://localhost:9200/xc_course/doc/_search

拿关键字 "spring css"去匹配name和description字段。

{
    "query": {
        "multi_match": {
            "query": "spring css",
            "minimum_should_match": "50%",
            "fields": [
                "name",
                "description"
            ]
        }
    }
}

2、提升boost

匹配多个字段时可以提升字段的boost(权重)来提高得分

提升boost之前,执行上边的查询,通过查询发现Bootstrap排在前边;提升boost,通常关键字匹配上name的权重要比匹配上description的权重高,这里可以对name的权重提升。

{
    "query": {
        "multi_match": {
            "query": "spring框架",
            "minimum_should_match": "50%",
            "fields": [
                "name^10",
                "description"
            ]
        }
    }
}

"name^10" 表示权重提升10倍,执行上边的查询,发现name中包括spring关键字的文档排在前边。

7、布尔查询

布尔查询对应于Lucene的BooleanQuery查询,实现将多个查询组合起来。

三个参数:

must:文档必须匹配must所包括的查询条件,相当于 "AND"

should:文档应该匹配should所包括的查询条件其中的一个或多个,相当于"OR"

must_not:文档不能匹配must_not所包括的该查询条件,相当于"NOT"

{
    "_source": [
        "name",
        "studymodel",
        "description"
    ],
    "from": 0,
    "size": 1,
    "query": {
        "bool": {
            "must": [
                {
                    "multi_match": {
                        "query": "spring框架",
                        "minimum_should_match": "50%",
                        "fields": [
                            "name^10",
                            "description"
                        ]
                    }
                },
                {
                    "term": {
                        "studymodel": "201001"
                    }
                }
            ]
        }
    }
}

8、过滤器

过滤是针对搜索的结果进行过滤,过滤器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分,所以过滤器性能比查询要高,且方便缓存,推荐尽量使用过滤器去实现查询或者过滤器和查询共同使用。 过滤器只在布尔查询中使用。

{
    "_source": [
        "name",
        "studymodel",
        "description",
        "price"
    ],
    "query": {
        "bool": {
            "must": [
                {
                    "multi_match": {
                        "query": "spring框架",
                        "minimum_should_match": "50%",
                        "fields": [
                            "name^10",
                            "description"
                        ]
                    }
                }
            ],
            "filter": [
                {
                    "term": {
                        "studymodel": "201001"
                    }
                },
                {
                    "range": {
                        "price": {
                            "gte": 60,
                            "lte": 100
                        }
                    }
                }
            ]
        }
    }
}

range:范围过虑,保留大于等于60 并且小于等于100的记录。

term:项匹配过虑,保留studymodel等于"201001"的记录。

注意:range和term一次只能对一个Field设置范围过虑。

9、排序

可以在字段上添加一个或多个排序,支持在keyword、date、float等类型上添加,text类型的字段上不允许添加排序。

// 过滤0--10元价格范围的文档,并且对结果进行排序,先按studymodel降序,再按价格升序
{
    "_source": [
        "name",
        "studymodel",
        "description",
        "price"
    ],
    "query": {
        "bool": {
            "filter": [
                {
                    "range": {
                        "price": {
                            "gte": 0,
                            "lte": 100
                        }
                    }
                }
            ]
        }
    },
    "sort": [
        {
            "studymodel": "desc"
        },
        {
            "price": "asc"
        }
    ]
}

10、高亮显示

高亮显示可以将搜索结果一个或多个字突出显示,以便向用户展示匹配关键字的位置。

在搜索语句中添加highlight即可实现,如下:

{
    "_source": [
        "name",
        "studymodel",
        "description",
        "price"
    ],
    "query": {
        "bool": {
            "must": [
                {
                    "multi_match": {
                        "query": "开发框架",
                        "minimum_should_match": "50%",
                        "fields": [
                            "name^10",
                            "description"
                        ],
                        "type": "best_fields"
                    }
                }
            ],
            "filter": [
                {
                    "range": {
                        "price": {
                            "gte": 0,
                            "lte": 100
                        }
                    }
                }
            ]
        }
    },
    "sort": [
        {
            "price": "asc"
        }
    ],
    "highlight": {
        "pre_tags": [
            "<tag>"
        ],
        "post_tags": [
            "</tag>"
        ],
        "fields": {
            "name": {},
            "description": {}
        }
    }
}

八、集群管理

1、集群结构

ES通常以集群方式工作,这样做不仅能够提高 ES的搜索能力还可以处理大数据搜索的能力,同时也增加了系统的 容错能力及高可用,ES可以实现PB级数据的搜索。

1)结点

ES集群由多个服务器组成,每个服务器即为一个Node结点(该服务只部署了一个ES进程)。

2)分片

当我们的文档量很大时,由于内存和硬盘的限制,同时也为了提高ES的处理能力、容错能力及高可用能力,我们将索引分成若干分片,每个分片可以放在不同的服务器,这样就实现了多个服务器共同对外提供索引及搜索服务。 一个搜索请求过来,会分别从各各分片去查询,最后将查询到的数据合并返回给用户。

3)副本

为了提高ES的高可用同时也为了提高搜索的吞吐量,我们将分片复制一份或多份存储在其它的服务器,这样即使当前的服务器挂掉了,拥有副本的服务器照常可以提供服务。

4)主结点

一个集群中会有一个或多个主结点,主结点的作用是集群管理,比如增加节点,移除节点等,主结点挂掉后ES会重新选一个主结点。

5)结点转发

每个结点都知道其它结点的信息,我们可以对任意一个结点发起请求,接收请求的结点会转发给其它结点查询数 据。

2、搭建集群

主结点:master节点主要用于集群的管理及索引 比如新增结点、分片分配、索引的新增和删除等。

数据结点:data节点上保存了数据分片,它负责索引和搜索操作。

客户端结点:client节点仅作为请求客户端存在,client的作用也作为负载均衡器,client节点不存数据,只是将请求均衡转发到其它结点。

通过下边两项参数来配置结点的功能:

node.master: #是否允许为主结点

node.data: #允许存储数据作为数据结点

node.ingest: #是否允许成为协调节点,

四种组合方式:

master=true,data=true:即是主结点又是数据结点

master=false,data=true:仅是数据结点

master=true,data=false:仅是主结点,不存储数据

master=false,data=false:即不是主结点也不是数据结点,此时可设置ingest为true表示它是一个客户端。

下边的例子实现创建一个2结点的集群,并且索引的分片我们设置2片,每片一个副本。

1)创建节点1

解压elasticsearch-6.2.1.zip 到 F:/elasticsearch/elasticsearch-1

节点1对外服务的http端口是:9200,集群管理端口是9300,配置elasticsearch.yml,结点名:xc_node_1

elasticsearch.yml内容如下:

cluster.name: xuecheng
node.name: xc_node_1
network.host: 0.0.0.0
http.port: 9200
transport.tcp.port: 9300
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["0.0.0.0:9300", "0.0.0.0:9301"]
discovery.zen.minimum_master_nodes: 1
node.ingest: true
node.max_local_storage_nodes: 2
path.data: F:\elasticsearch\elasticsearch-1\data
path.logs: F:\elasticsearch\elasticsearch-1\logs
http.cors.enabled: true
http.cors.allow‐origin: /.*/

进入bin目录,运行bat脚本,启动节点1。

2)创建节点2

解压elasticsearch-6.2.1.zip 到 F:/elasticsearch/elasticsearch-2

节点2对外服务的http端口是:9201,集群管理端口是9301,配置elasticsearch.yml,结点名:xc_node_2

elasticsearch.yml内容如下:

cluster.name: xuecheng
node.name: xc_node_2
network.host: 0.0.0.0
http.port: 9201
transport.tcp.port: 9301
node.master: true
node.data: true
discovery.zen.ping.unicast.hosts: ["0.0.0.0:9300", "0.0.0.0:9301"]
discovery.zen.minimum_master_nodes: 1
node.ingest: true
node.max_local_storage_nodes: 2
path.data: F:\elasticsearch\elasticsearch-2\data
path.logs: F:\elasticsearch\elasticsearch-2\logs
http.cors.enabled: true
http.cors.allow‐origin: /.*/

进入bin目录,运行bat脚本,启动节点1。

3)创建索引库

// 使用Put请求:http://localhost:9200/xc_test
// 创建2分片,1个副本;发送的数据为:
{
    "settings": {
        "number_of_shards": 2,
        "number_of_replicas": 1
    }
}

3、集群的健康

通过Get请求:/_cluster/health 来查看Elasticsearch的集群健康情况。

用三种颜色来展示健康状态:green、yellow或者red。green:所有的主分片和副本分片都正常运行。yellow:所有的主分片都正常运行,但有些副本分片运行不正常。red:存在主分片运行不正常。

Get请求:http://localhost:9200/_cluster/health

// 响应的数据为:
{
    "cluster_name": "xuecheng",
    "status": "green",
    "timed_out": false,
    "number_of_nodes": 2,
    "number_of_data_nodes": 2,
    "active_primary_shards": 2,
    "active_shards": 4,
    "relocating_shards": 0,
    "initializing_shards": 0,
    "unassigned_shards": 0,
    "delayed_unassigned_shards": 0,
    "number_of_pending_tasks": 0,
    "number_of_in_flight_fetch": 0,
    "task_max_waiting_in_queue_millis": 0,
    "active_shards_percent_as_number": 100.0
}
ElasticSearch
全文搜索技术
  • 作者:lzlg520
  • 发表时间:2020-06-16 03:39
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 公众号转载:请在文末添加作者公众号二维码