ElasticSearch高级 (Query DSL查询 bulk批量操作 导入数据 各种查询 实战技巧-优化比重 全量与增量数据同步)

本文介绍Elasticsearch中的高级查询技术,包括Query DSL、全文检索、精准查询、组合查询等内容,并提供Java API示例代码。此外还涵盖批量操作、数据导入、聚合查询、高亮查询等实用技巧。

01-Query DSL(Domain Specific Language)

1 查询上下文

​ 使用query关键字进行检索,倾向于相关度搜索,故需要计算评分。搜索是Elasticsearch最关键和重要的部分。

2 相关度评分:_score

​ 概念:相关度评分用于对搜索结果排序,评分越高则认为其结果和搜索的预期值相关度越高,即越符合搜索预期值。在7.x之前相关度评分默认使用TF/IDF算法计算而来,7.x之后默认为BM25。在核心知识篇不必关心相关评分的具体原理,只需知晓其概念即可。

​ 排序:相关度评分为搜索结果的排序依据,默认情况下评分越高,则结果越靠前。

3 元数据:_source

  1. 禁用_source:

    1. 好处:节省存储开销

    2. 坏处:

      • 不支持update、update_by_query和reindex API。
      • 不支持高亮。
      • 不支持reindex、更改mapping分析器和版本升级。
      • 通过查看索引时使用的原始文档来调试查询或聚合的功能。
      • 将来有可能自动修复索引损坏。

      总结:如果只是为了节省磁盘,可以压缩索引比禁用_source更好。

  2. 数据源过滤器:

    Including:结果中返回哪些field

    Excluding:结果中不要返回哪些field,不返回的field不代表不能通过该字段进行检索,因为元数据不存在不代表索引不存在

    1. 在mapping中定义过滤:支持通配符,但是这种方式不推荐,因为mapping不可变
PUT product
{
   
   
  "mappings": {
   
   
    "_source": {
   
   
      "includes": [
        "name",
        "price"
      ],
      "excludes": [
        "desc",
        "tags"
      ]
    }
  }
}
  1. 常用过滤规则

   "_source": "false", 

   "_source": "obj.*", 

   "_source": [ "obj1.\*", "obj2.\*" ],

    "_source": {
   
   
     "includes": [ "obj1.\*", "obj2.\*" ],
     "excludes": [ "*.description" ]
       }

4 Query String

  • 查询所有:

    GET /product/_search

  • 带参数:

    GET /product/_search?q=name:xiaomi

  • 分页:

    GET /product/_search?from=0&size=2&sort=price:asc

  • 精准匹配 exact value

    GET /product/_search?q=date:2021-06-01

  • _all搜索 相当于在所有有索引的字段中检索

    GET /product/_search?q=2021-06-01

5 全文检索-Fulltext query

GET index/_search
{
  "query": {
    ***
  }
}
  • match:匹配包含某个term的子句
  • match_all:匹配所有结果的子句
  • multi_match:多字段条件
  • match_phrase:短语查询,

6 精准查询-Term query

  • term:匹配和搜索词项完全相等的结果
    • term和match_phrase区别:

      match_phrase 会将检索关键词分词, match_phrase的分词结果必须在被检索字段的分词中都包含,而且顺序必须相同,而且默认必须都是连续的

      term搜索不会将搜索词分词

    • term和keyword区别

      term是对于搜索词不分词,

      keyword是字段类型,是对于source data中的字段值不分词

  • terms:匹配和搜索词项列表中任意项匹配的结果
  • range:范围查找

    7 过滤器-Filter

GET _search
{
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "status": "active"
        }
      }
    }
  }
}
  • filter:query和filter的主要区别在: filter是结果导向的而query是过程导向。query倾向于“当前文档和查询的语句的相关度”而filter倾向于“当前文档和查询的条件是不是相符”。即在查询过程中,query是要对查询的每个结果计算相关性得分的,而filter不会。另外filter有相应的缓存机制,可以提高查询效率。

    8 组合查询-Bool query

bool:可以组合多个查询条件,bool查询也是采用more_matches_is_better的机制,因此满足must和should子句的文档将会合并起来计算分值

  • must:必须满足子句(查询)必须出现在匹配的文档中,并将有助于得分。
  • filter:过滤器 不计算相关度分数,cache☆子句(查询)必须出现在匹配的文档中。但是不像 must查询的分数将被忽略。Filter子句在filter上下文中执行,这意味着计分被忽略,并且子句被考虑用于缓存。
  • should:可能满足 or子句(查询)应出现在匹配的文档中。
  • must_not:必须不满足 不计算相关度分数 not子句(查询)不得出现在匹配的文档中。子句在过滤器上下文中执行,这意味着计分被忽略,并且子句被视为用于缓存。由于忽略计分,0因此将返回所有文档的分数。

minimum_should_match:参数指定should返回的文档必须匹配的子句的数量或百分比。如果bool查询包含至少一个should子句,而没有must或 filter子句,则默认值为1。否则,默认值为0

02-ElasticSearch高级操作

2.1-bulk批量操作-脚本

脚本:

测试用的5号文档

POST /person1/_doc/5
{
  "name":"张三5号",
  "age":18,
  "address":"北京海淀区"
}

批量操作文本

#批量操作
#1.删除5号
#新增8号
#更新2号 name为2POST _bulk
{
   
   "delete":{
   
   "_index":"person1","_id":"5"}}
{
   
   "create":{
   
   "_index":"person1","_id":"8"}}
{
   
   "name":"八号","age":18,"address":"北京"}
{
   
   "update":{
   
   "_index":"person1","_id":"2"}}
{
   
   "doc":{
   
   "name":"2号"}}

结果

{
   
   
  "took" : 51,
  "errors" : true,
  "items" : [
    {
   
   
      "delete" : {
   
   
        "_index" : "person1",
        "_type" : "_doc",
        "_id" : "5",
        "_version" : 2,
        "result" : "deleted",
        "_shards" : {
   
   
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 6,
        "_primary_term" : 2,
        "status" : 200
      }
    },
    {
   
   
      "create" : {
   
   
        "_index" : "person1",
        "_type" : "_doc",
        "_id" : "8",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
   
   
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 7,
        "_primary_term" : 2,
        "status" : 201
      }
    },
    {
   
   
      "update" : {
   
   
        "_index" : "person1",
        "_type" : "_doc",
        "_id" : "2",
        "_version" : 2,
        "result" : "updated",
        "_shards" : {
   
   
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 10,
        "_primary_term" : 2,
        "status" : 200
      }
    }
  ]
}

2.2-bulk批量操作-JavaAPI

 /**
     *  Bulk 批量操作
     */
    @Test
    public void test2() throws IOException {
   
   

        //创建bulkrequest对象,整合所有操作
        BulkRequest bulkRequest =new BulkRequest();

           /*
        # 1. 删除5号记录
        # 2. 添加6号记录
        # 3. 修改3号记录 名称为 “三号”
         */
        //添加对应操作
        //1. 删除5号记录
        DeleteRequest deleteRequest=new DeleteRequest("person1","5");
        bulkRequest.add(deleteRequest);

        //2. 添加6号记录
        Map<String, Object> map=new HashMap<>();
        map.put("name","六号");
        IndexRequest indexRequest=new IndexRequest("person1").id("6").source(map);
        bulkRequest.add(indexRequest);
        //3. 修改3号记录 名称为 “三号”
        Map<String, Object> mapUpdate=new HashMap<>();
        mapUpdate.put("name","三号");
        UpdateRequest updateRequest=new UpdateRequest("person1","3").doc(mapUpdate);

        bulkRequest.add(updateRequest);
        //执行批量操作


        BulkResponse response = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(response.status());

    }

2.3-导入数据-分析&创建索引

PUT goods
{
   
   
	"mappings": {
   
   
		"properties": {
   
   
			"title": {
   
   
				"type": "text",
				"analyzer": "ik_smart"
			},
			"price": {
   
    
				"type": "double"
			},
			"createTime": {
   
   
				"type": "date"
			},
			"categoryName": {
   
   	
				"type": "keyword"
			},
			"brandName": {
   
   	
				"type": "keyword"
			},
	
			"spec": {
   
   		
				"type": "object"
			},
			"saleNum": {
   
   	
				"type": "integer"
			},
			
			"stock": {
   
   	
				"type": "integer"
			}
		}
	}
}

2.4-导入数据-代码实现

需要链接数据库,然后建立对应字段,因为查询来的数据是String,需要先解析成对象,然后把整个good对象转成mapper放入其中
在这里插入图片描述
good

package com.ybb.domain;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.beans.factory.annotation.Value;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;

/**
 * Description :
 * Version :1.0
 */
public class Good implements Serializable {
   
   

    private Integer id;
    private String title;
    private Integer price;
    private String stock;
    private Integer saleNum;
    private Date createTime;
    private String categoryName;
    private String brandName;
    private Map spec;
    @JSONField(serialize = false)
    private String specStr;

    public Integer getId() {
   
   
        return id;
    }

    public void setId(Integer id) {
   
   
        this.id = id;
    }

    public String getTitle() {
   
   
        return title;
    }

    public void setTitle(String title) {
   
   
        this.title = title;
    }

    public Integer getPrice() {
   
   
        return price;
    }

    public void setPrice(Integer price) {
   
   
        this.price = price;
    }

    public String getStock() {
   
   
        return stock;
    }

    public void setStock(String stock) {
   
   
        this.stock = stock;
    }

    public Integer getSaleNum() {
   
   
        return saleNum;
    }

    public void setSaleNum(Integer saleNum) {
   
   
        this.saleNum = saleNum;
    }

    public Date getCreateTime() {
   
   
        return createTime;
    }

    public void setCreateTime(Date createTime) {
   
   
        this.createTime = createTime;
    }

    public String getCategoryName() {
   
   
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
   
   
        this.categoryName = categoryName;
    }

    public String getBrandName() {
   
   
        return brandName;
    }

    public void setBrandName(String brandName) {
   
   
        this.brandName = brandName;
    }

    public Map getSpec() {
   
   
        return JSON.parseObject(specStr,Map.class);
    }

    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值