elasticsearchCRUD
索引库操作
创建索引库
mapping是对索引库中文档的约束,常见的mapping属性包括:
- type:字段数据类型,常见的简单类型有:
- 字符串:text(可分词的文本)、keyword(精确值,例如:品牌、国家、ip地址)
- 数值:long、integer、short、byte、double、float、
- 布尔:boolean
- 日期:date
- 对象:object
- location:地理坐标,里面包含精度、纬度
- all:一个组合字段,其目的是将多字段的值 利用copy_to合并,提供给用户搜索
- index:是否创建索引,默认为true
- analyzer:使用哪种分词器
- properties:该字段的子字段
基础语法
PUT /索引库名称
{
"mappings": {
"properties": {
"字段名":{
"type": "text",
"analyzer": "ik_smart",
"copy_to": "all"
},
"字段名2":{
"type": "keyword",
"index": "false",
"copy_to": "all"
},
"字段名3":{
"properties": {
"子字段": {
"type": "keyword"
}
}
},
"all":{
"type": "keyword",
"index": "false"
},
// ...略
}
}
}
查询索引库
基本语法:
GET /索引库名
添加索引库
注意:因此索引库一旦创建,无法修改mapping,但可以添加
基本语法:
PUT /索引库名/_mapping
{
"properties": {
"新字段名":{
"type": "integer"
}
}
}
删除索引库
基本语法:
DELETE /索引库名
总结
- 创建索引库:PUT /索引库名
- 查询索引库:GET /索引库名
- 删除索引库:DELETE /索引库名
- 添加字段:PUT /索引库名/_mapping
文档操作
新增文档
基本语法:
POST /索引库名/_doc/文档id
{
"字段1": "值1",
"字段2": "值2",
"字段3": {
"子属性1": "值3",
"子属性2": "值4"
},
// ...
}
删除文档
基本语法:
DELETE /{索引库名}/_doc/id值
修改文档
注意:如果根据id删除时,id不存在,第二步的新增也会执行,也就从修改变成了新增操作了。
全量修改
基本语法:
PUT /{索引库名}/_doc/文档id
{
"字段1": "值1",
"字段2": "值2",
// ... 略
}
增量修改
基本语法:
POST /{索引库名}/_update/文档id
{
"doc": {
"字段名": "新的值",
}
}
总结
- 创建文档:POST /{索引库名}/_doc/文档id { json文档 }
- 查询文档:GET /{索引库名}/_doc/文档id
- 删除文档:DELETE /{索引库名}/_doc/文档id
- 修改文档:
- 全量修改:PUT /{索引库名}/_doc/文档id { json文档 }
- 增量修改:POST /{索引库名}/_update/文档id { “doc”: {字段}}
DSL查询文档
由于查询文档内容过多,单独拿出来写
基本语发模板
GET /indexName/_search
{
"query": {
"查询类型": {
"查询条件": "条件值"
}
}
}
全文检索
match查询:单字段查询
基本语法
GET /indexName/_search
{
"query": {
"match": {
"字段名": "查询的内容"
}
}
}
multi_match查询:多字段查询,任意一个字段符合条件就算符合查询条件
基本语法
# 这种写法和 copy_to 将字段提取出来效果一样
GET /indexName/_search
{
"query": {
"multi_match": {
"query": "查询的内容",
"fields": ["字段名1", " 字段名2"]
}
}
}
总结
- match:根据一个字段查询
- multi_match:根据多个字段查询,参与查询字段越多,查询性能越差
精准查询
term:根据词条精确值查询
注意:因为精确查询的字段搜是不分词的字段,因此查询的条件也必须是不分词的词条;
基本语法
// term查询
GET /indexName/_search
{
"query": {
"term": {
"FIELD": {
"value": "VALUE"
}
}
}
}
range:根据值的范围查询
范围查询,一般应用在对数值类型做范围过滤的时候。比如做价格范围过滤。
基本语法:
// range查询
GET /indexName/_search
{
"query": {
"range": {
"FIELD": {
"gte": 10, // 这里的gte代表大于等于,gt则代表大于
"lte": 20 // lte代表小于等于,lt则代表小于
}
}
}
}
总结
- term查询:根据词条精确匹配,一般搜索keyword类型、数值类型、布尔类型、日期类型字段
- range查询:根据数值范围查询,可以是数值、日期的范围
地理坐标查询
矩形范围查询(geo_bounding_box查询)
基本语法:
// geo_bounding_box查询
GET /indexName/_search
{
"query": {
"geo_bounding_box": {
"FIELD": {
"top_left": { // 左上点
"lat": 31.1, //纬度
"lon": 121.5 //经度
},
"bottom_right": { // 右下点
"lat": 30.9,
"lon": 121.7
}
}
}
}
}
附近查询(geo_distance)
基本语法:
// geo_distance 查询
GET /indexName/_search
{
"query": {
"geo_distance": {
"distance": "15km", // 半径
"FIELD": "31.21,121.5" // 圆心
}
}
}
复合查询
fuction score:算分函数查询,可以控制文档相关性算分,控制文档排名
基本语法:
GET /hotel/_search
{
"query": {
"function_score": {
"query": { .... }, // 原始查询,可以是任意条件
"functions": [ // 算分函数
{
"filter": { // 满足的条件,品牌必须是如家
"term": {
"brand": "如家"
}
},
// weight:函数结果是常量
// field_value_factor:以文档中的某个字段值作为函数结果
// random_score:以随机数作为函数结果
// script_score:自定义算分函数算法
"weight": 2 // 算分权重为2
}
],
// multiply(乘)、sum(加)、avg(平均)、max(最大)、min(最小)
"boost_mode": "sum" // 加权模式,求和
}
}
}
总结
function score query定义的三要素是什么?
- 过滤条件:哪些文档要加分
- 算分函数:如何计算function score
- 加权方式:function score 与 query score如何运算
bool query:布尔查询,利用逻辑关系组合多个其它的查询,实现复杂搜索
GET /hotel/_search
{
"query": {
"bool": {
"must": [ // 必须匹配每个子查询,类似“与”
{"term": {"city": "上海" }}
],
"should": [ // 选择性匹配子查询,类似“或”
{"term": {"brand": "皇冠假日" }},
{"term": {"brand": "华美达" }}
],
"must_not": [ // 必须不匹配,**不参与算分**,类似“非”
{ "range": { "price": { "lte": 500 } }}
],
"filter": [ // 必须匹配,**不参与算分**
{ "range": {"score": { "gte": 45 } }}
]
}
}
}
搜索结果处理
排序
elasticsearch默认是根据相关度算分(_score)来排序,但是也支持自定义方式对搜索结果排序。可以排序字段类型有:keyword类型、数值类型、地理坐标类型、日期类型等。
普通字段排序
keyword、数值、日期类型排序的语法基本一致。
基本语法:
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"FIELD": "desc" // 排序字段、排序方式ASC、DESC
}
]
}
地理坐标排序
提示:获取你的位置的经纬度的方式:https://lbs.amap.com/demo/jsapi-v2/example/map/click-to-get-lnglat/
基本语法
GET /indexName/_search
{
"query": {
"match_all": {}
},
"sort": [
{
"_geo_distance" : {
"FIELD" : "纬度,经度", // 文档中geo_point类型的字段名、目标坐标点
"order" : "asc", // 排序方式
"unit" : "km" // 排序的距离单位
}
}
]
}
分页
- from:从第几个文档开始
- size:总共查询几个文档
基本的分页
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 0, // 分页开始的位置,默认为0
"size": 10, // 期望获取的文档总数
"sort": [
{"price": "asc"}
]
}
深度分页问题
GET /hotel/_search
{
"query": {
"match_all": {}
},
"from": 990, // 分页开始的位置,默认为0
"size": 10, // 期望获取的文档总数
"sort": [
{"price": "asc"}
]
}
总结
分页查询的常见实现方案以及优缺点:
from + size
:
- 优点:支持随机翻页
- 缺点:深度分页问题,默认查询上限(from + size)是10000
- 场景:百度、京东、谷歌、淘宝这样的随机翻页搜索
after search
:
- 优点:没有查询上限(单次查询的size不超过10000)
- 缺点:只能向后逐页查询,不支持随机翻页
- 场景:没有随机翻页需求的搜索,例如手机向下滚动翻页
scroll
:
- 优点:没有查询上限(单次查询的size不超过10000)
- 缺点:会有额外内存消耗,并且搜索结果是非实时的
- 场景:海量数据的获取和迁移。从ES7.1开始不推荐,建议用 after search方案。
高亮
- 1)给文档中的所有关键字都添加一个标签,例如
<em>
标签- 2)页面给
<em>
标签编写CSS样式
基本语法:
GET /hotel/_search
{
"query": {
"match": {
"FIELD": "TEXT" // 查询条件,高亮一定要使用全文检索查询
}
},
"highlight": {
"fields": { // 指定要高亮的字段
"FIELD": {
"pre_tags": "<em>", // 用来标记高亮字段的前置标签
"post_tags": "</em>" // 用来标记高亮字段的后置标签
}
}
}
}
注意:
- 高亮是对关键字高亮,因此搜索条件必须带有关键字,而不能是范围这样的查询。
- 默认情况下,高亮的字段,必须与搜索指定的字段一致,否则无法高亮
- 如果要对非搜索字段高亮,则需要添加一个属性:required_field_match=false
常用属性
query
: 定义查询条件的主要属性,用于指定匹配的规则。size
: 指定返回的文档数量,即每页的文档数。from
: 指定从搜索结果的第几个文档开始返回,用于分页。sort
: 指定排序规则,用于按照指定字段对搜索结果进行排序。_source
: 控制返回的文档字段,可以指定需要包含或排除的字段。aggs
: 定义聚合操作,用于对搜索结果进行统计、分组等操作。highlight
: 高亮显示匹配的字段,使匹配部分更容易识别。script_fields
: 使用脚本生成字段,可以在搜索结果中添加计算得到的字段。post_filter
: 在查询结果上应用后过滤器,用于对搜索结果进行二次过滤。min_score
: 设置最小匹配分数,只返回匹配分数达到指定值的文档。timeout
: 设置查询的超时时间,指定查询操作的最大执行时间。terminate_after
: 查询超过指定数量后立即终止,用于控制查询的最大执行文