最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot簡(jiǎn)單整合ElasticSearch實(shí)踐

 更新時(shí)間:2025年12月06日 10:21:06   作者:Kevin_wcl  
Elasticsearch支持結(jié)構(gòu)化和非結(jié)構(gòu)化數(shù)據(jù)檢索,通過索引創(chuàng)建和倒排索引文檔,提高搜索效率,它基于Lucene封裝,分為索引庫、類型、文檔和字段,Spring Boot可方便操作ES,通過依賴配置、實(shí)體類映射和ElasticsearchRepository接口實(shí)現(xiàn)CRUD操作

一:ElasticSearch支持對(duì)結(jié)構(gòu)化和非結(jié)構(gòu)化的數(shù)據(jù)進(jìn)行檢索

我的理解是:把采集的數(shù)據(jù)(一般是從數(shù)據(jù)庫中的數(shù)據(jù)如商品數(shù)據(jù))轉(zhuǎn)化為`一種有結(jié)構(gòu)的數(shù)據(jù)`進(jìn)行搜索,從而提高搜索效率,通常而言有結(jié)構(gòu)的數(shù)據(jù)`查詢是比較快`的。而這種結(jié)構(gòu)在ES中被叫做 - `倒排索引文檔`.

數(shù)據(jù)轉(zhuǎn)換為倒排索引文檔的整個(gè)過程叫`索引創(chuàng)建`,如下圖:

原始數(shù)據(jù)經(jīng)過:分詞,詞大小寫轉(zhuǎn)換,自然排序,單詞合并形成倒排索引。

  • 1.分詞需要使用到分詞器,對(duì)于中文的內(nèi)容更要使用中文分詞器,比如:IK分詞器
  • 2.為了方便搜索,忽略大小寫敏感所以進(jìn)行了詞態(tài)和大小寫轉(zhuǎn)換
  • 3.單詞進(jìn)行排序,有序的數(shù)據(jù)可以提高查詢速度,比如二分查找
  • 4.相同單詞進(jìn)行合并后單詞只需要進(jìn)行一次搜索即可。

ElasticSearch基于Lucene進(jìn)行封裝的,對(duì)于ElasticSearch來說他的數(shù)據(jù)是進(jìn)行分片存儲(chǔ)的,而一個(gè)分片就是一個(gè)Lucene的索引庫,而Lucene的索引庫分為索引區(qū)和數(shù)據(jù)區(qū)兩部分。

結(jié)構(gòu)如下:

二:ES的核心概念

Index:索引庫

index被叫做索引庫,類似于Mysql的數(shù)據(jù)庫database ; 一個(gè)index中包含一堆有相似結(jié)構(gòu)的文檔數(shù)據(jù)(Document),比如說建立一個(gè)Goods index 商品索引,里面可能就存放了所有的商品數(shù)據(jù),通常一個(gè)商品數(shù)據(jù)(一行數(shù)據(jù))在ES中被描述為一個(gè)document。

Type:類型

每個(gè)索引里都可以有一個(gè)或多個(gè)type,type是index中的一個(gè)邏輯數(shù)據(jù)分類,一個(gè)type下的document,都有相同的field,就好比一個(gè)表中的多行數(shù)據(jù)擁有相同的列 。在ES 7.x以上的版本中取消了這個(gè)邏輯分類。

Document&field

document是一個(gè)文檔數(shù)據(jù),也是ES中的最小數(shù)據(jù)單元,一個(gè)document 可以是一條商品數(shù)據(jù),一個(gè)訂單數(shù)據(jù),通常用JSON數(shù)據(jù)結(jié)構(gòu)表示,每個(gè)index下的type中,都可以去存儲(chǔ)多個(gè)document。一個(gè)document里面有多個(gè)field,每個(gè)field就是一個(gè)數(shù)據(jù)字段。

索引庫index的CRUD

索引庫有點(diǎn)像關(guān)系型數(shù)據(jù)庫的database數(shù)據(jù)庫,比如:對(duì)于商品數(shù)據(jù)我們可以建立一個(gè)索引庫,對(duì)于訂單數(shù)據(jù)庫我們也可以建立一個(gè)索引庫

# 創(chuàng)建索引庫

PUT /orders
{
	"settings":{
		"number_of_shards":5,	
		"number_of_replicas":1
	}
}
  • number_of_shards : 主分片數(shù)量
  • number_of_replicas :每個(gè)主分片有一個(gè)備分片

文檔映射

ES的文檔映射(mapping)機(jī)制用于進(jìn)行字段類型確認(rèn),將每個(gè)字段匹配為一種確定的數(shù)據(jù)類型,也就是說我們存儲(chǔ)到ES中的數(shù)據(jù)到底用什么類型去存儲(chǔ)。

就如同Mysql創(chuàng)建表時(shí)候指定的每個(gè)column列的類型。 為了方便字段的檢索,我們會(huì)指定存儲(chǔ)在ES中的字段是否進(jìn)行分詞,但是有些字段類型可以分詞,有些字段類型不可以分詞,所以對(duì)于字段的類型需要我們自己去指定。 所以我們的ES的操作流程應(yīng)該是 

  • 1.創(chuàng)建索引
  • 2.創(chuàng)建映射 
  • 3.添加數(shù)據(jù)

ES中的數(shù)據(jù)類型

  • 字符串:常用的類型有 text(分詞) ;keyword(不分詞) ;如果某個(gè)字段被指定為text那么這個(gè)字段的值就會(huì)被分詞然后創(chuàng)建倒排索引。 如果是keyword也會(huì)創(chuàng)建倒排索引,只不過是把字段的值作為整體形成倒排索引,不會(huì)分詞。
  • 數(shù)字:與Java差不多。有 long ; integer ; short ; double ; float
  • 日期:date
  • 邏輯:boolean
  • 對(duì)象:Object
  • 數(shù)組:array
  • 位置:geo_point;geo_shape

創(chuàng)建簡(jiǎn)單映射

語法:

PUT /索引名
{
  "mappings": {
    "properties": {
      "字段名": {
        "type": "類型"
      }
    }
  }
}

例如:創(chuàng)建訂單索引庫(orders),該索引庫中的字段有id,title,amount,count;

id 使用long類型 ,title使用text類型(分詞且索引),amount使用double ,count使用 integer類型。

PUT /orders
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "id": {
        "type": "long"
      },
      "title": {
        "type": "text"
      },
      "amount":{
        "type": "double"
      },
      "count":{
        "type": "integer"
      }
    }
  }
}

文檔的CRUD

數(shù)據(jù)是以Docuement進(jìn)行存儲(chǔ),通常一行數(shù)據(jù)就是一個(gè)Document。

添加文檔

語法 `PUT index/type/id` : index是索引庫 ,type是類型 ,id是文檔的ID 。添加一個(gè)訂單數(shù)據(jù)演示如下:

PUT orders/_doc/1
{
	"id":1,
    "title":"買了個(gè)表",
    "amount":120.00,
    "count":1
}

獲取文檔

語法 `GET index/type/id`

GET orders/_doc/1

修改文檔

  • 全量修改:全量修改文檔和添加文檔的語法一樣 ,只要ID已經(jīng)存在,那么添加就會(huì)變成修改,當(dāng)時(shí)要注意,之所以叫全量修改是如果已有的數(shù)據(jù)是 4個(gè)列,而修改的數(shù)據(jù)只給了3個(gè)列,那么最終的數(shù)據(jù)就只有3個(gè)列。
  • 局部修改:只是修改指定的列,其他列不動(dòng),語法:
POST /index/_update/id
{
    "doc":{
        "列" : 值, 
        "列": "值"
    }
}

例如:

POST orders/_update/1
{
    "doc":{
        "amount" : 150.00
    }
}

ES簡(jiǎn)單查詢

# 查詢所有數(shù)據(jù)
GET orders/_search

# 查詢分頁  size是每頁條數(shù); from是跳過的條數(shù),和mysql的limit是一樣的含義,效果如下:
GET orders/_search?size=2&from=2

# 攜帶查詢參數(shù)可以通過 q= ,比如查詢count為1的
GET orders/_search?q=count:1&size=10&from=0

# 需要帶排序條件通過 sort=列:desc 指定 desc是倒排,正排是asc ,比如按在價(jià)格倒排
GET orders/_search?q=count:1&sort=amount:desc&size=10&from=0

ES條件查詢

match : 標(biāo)準(zhǔn)匹配,會(huì)把搜索的關(guān)鍵字分詞后再進(jìn)行匹配,效果如同: where title = 鼠 or title = 標(biāo)

GET /orders/_search
{
  "query": {
    "match": {
      "title": "了"
    }
  },
  "from": 0,
  "size": 10,
  "_source": [
    "id",
    "title",
    "amount",
    "count"
  ],
  "sort": [
    {
      "amount": "desc"
    }
  ]
}
  • bool:代表的是組合查詢,把多種查詢方式組合到一起,bool下面包含了must和filter;must和filter里面都可以包含多個(gè)查詢條件
  • must:bool組合了must和filter , must中的語句是DSL查詢,filter中的語句是DSL過濾。must代表其中的條件是必須滿足,還可以把must指定為 should 和 must_not;這個(gè)位置的語句會(huì)進(jìn)行相關(guān)性計(jì)算,且按照分?jǐn)?shù)排序,一般會(huì)把關(guān)鍵字查詢放到這里。

should下面會(huì)帶一個(gè)以上的條件,至少滿足一個(gè)條件,這個(gè)文檔就符合should

  • must_not : 文檔必須不匹配條件
  • filter : 過濾,里面的查詢語句不會(huì)處理相關(guān)性等,但是會(huì)對(duì)查詢的結(jié)果進(jìn)行緩存,性能好
  • range : 指的是范圍 ;get是大于等于 ;let是小于等于
  • term :詞元匹配,可以理解為精準(zhǔn)匹配,可以用于字符串,數(shù)字等類型
  • from : 第2頁應(yīng)該是 (2 - 1 )* 每頁條數(shù)10
GET /orders/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "買了個(gè)表"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "amount": {
              "gte": 100,
              "lte": 200
            }
          }
        }
      ]
    }
  },
  "from": 0,
  "size": 10,
  "sort": [
    {
      "amount": "desc"
    }
  ]
}

高亮查詢

GET /orders/_search
{
    "query" : {
        "match": { "title": "鼠標(biāo)" }
    },
    "highlight" : {
        "fields" : {
            "title": {
                "pre_tags": [
                    "<span style='color:red'>"
                ],
                "post_tags": [
                    "</span>"
                ]
            }
        }
    }
}

三:SpringBoot操作ES

3.1 導(dǎo)入SpringBoot整合ES的依賴

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

3.2 application.yml配置

yml中對(duì)ES進(jìn)行配置 , 如果是集群配置增加uri即可,單個(gè)配置如下:

spring:
  elasticsearch:
    rest:
      uris: http://192.168.231.128:9200

3.3 編寫Document對(duì)象 ,該對(duì)象是對(duì)存儲(chǔ)到ES中的數(shù)據(jù)的封裝,同時(shí)文檔映射也是通過它來實(shí)現(xiàn)

package com.wcl.es.doc;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.math.BigDecimal;

//標(biāo)記該對(duì)象是ES的文檔對(duì)象
//indexName 索引庫
//type 類型
@Document(indexName = "orders",type = "_doc")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OrderDoc {

    //標(biāo)記為文檔ID,該ID的值會(huì)作為document的id值
    @Id
    private Long id;
    /**
     * 標(biāo)題需要分詞,指定為text;并使用IK分詞器
     * 一般需要作為關(guān)鍵字搜索的字段都要指定為text,因?yàn)樾枰衷~且創(chuàng)建索引
     */
    @Field(type = FieldType.Text,analyzer = "ik_max_word",searchAnalyzer = "ik_max_word")
    //@Field(type = FieldType.Keyword)
    private String title;

    /**
     * 指定為integer類型
     */
    @Field(type = FieldType.Integer)
    private int count;

    /**
     * 狀態(tài)指定為 integer類型
     */
    @Field(type = FieldType.Integer)
    private int status;

    /**
     * 金額
     */
    @Field(type = FieldType.Double)
    private BigDecimal amount;

}

3.4 SpringBootData提供了ElasticsearchRepository 來操作ES,該接口中包含了針對(duì)ES的CRUD方法,我們編寫接口集成它即可使用

@Repository
public interface OrderRepository extends ElasticsearchRepository<OrderDoc,Long> {
}

3.5 新建測(cè)試service類,注入

    @Autowired
    private OrdersRepository ordersRepository;
    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

3.6 測(cè)試

創(chuàng)建索引庫

    public void createIndex() {
        // 創(chuàng)建索引庫
        elasticsearchTemplate.createIndex(OrderDoc.class);
        // 創(chuàng)建映射
        elasticsearchTemplate.putMapping(OrderDoc.class);
    }

查詢數(shù)據(jù)

    public void findById() {
        Optional<OrderDoc> byId = ordersRepository.findById(1L);
        System.out.println(byId.get());
    }

刪除數(shù)據(jù)

    public void deleteById() {
        ordersRepository.deleteById(1L);
    }

新增(修改)數(shù)據(jù)

    public void addData() {
        ordersRepository.save(
                new OrderDoc(
                        3L,
                        "測(cè)試數(shù)據(jù)1",
                        1,
                        1,
                        new BigDecimal(1)
                )
        );
    }

條件查詢

組合查詢:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "title": "買了個(gè)表"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "amount": {
              "gte": 100,
              "lte": 200
            }
          },
		  "term":{
			 "status":1
		  }
        }
      ]
    }
  },
  "from": 0,
  "size": 10,
  "sort": [
    {
      "amount": "desc"
    }
  ]
}

該語句在java中的寫法:

     public void search(){
        // 查詢構(gòu)建器
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        // 設(shè)置分頁 0 頁數(shù)  10 每頁顯示多少條
        builder.withPageable(PageRequest.of(0, 10));

        // 設(shè)置排序(根據(jù)自己設(shè)置的字段排序)
        builder.withSort(SortBuilders.fieldSort("amount").order(SortOrder.DESC));

        // 構(gòu)建組合查詢 bool
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        // must:{match:{title:"鼠標(biāo)"}}
        boolQueryBuilder.must(QueryBuilders.matchQuery("title", "鼠標(biāo)"))
                // filter:{range:{amount:{gte:100,lte:200}}}
                .filter(QueryBuilders.rangeQuery("amount").gte(100).lte(200))
                // filter:{term:{status:1}}
                .filter(QueryBuilders.termQuery("status", 1));

        // 添加查詢條件
        builder.withQuery(boolQueryBuilder);

        // 執(zhí)行查詢
        Page<OrderDoc> page = ordersRepository.search(builder.build());
        // 獲取條數(shù)
        long total = page.getTotalElements();
        System.out.println("總條數(shù):" + total);
        // 獲取列表
        page.getContent().forEach(System.out::println);

    }

高亮查詢

{
    "query" : {
        "match": { "title": "鼠標(biāo)" }
    },
    "highlight" : {
        "fields" : {
            "title": {
                "pre_tags": [
                    "<span style='color:red'>"
                ],
                "post_tags": [
                    "</span>"
                ]
            }
        }
    }
}

該語句在java中的寫法

    public void highlight(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        builder.withQuery(QueryBuilders.matchQuery("title", "鼠標(biāo)"));
        // 設(shè)置高亮
        // 高亮的字段 fields.title
        HighlightBuilder.Field highlightField = new HighlightBuilder.Field("title")
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        // 設(shè)置高亮
        builder.withHighlightFields(highlightField);


        Page<OrderDoc> orderDocs = elasticsearchTemplate.queryForPage(
                builder.build(),
                OrderDoc.class,
                new HighlightResultMapper()
        );

        // 獲取條數(shù)
        long total = orderDocs.getTotalElements();
        System.out.println("總條數(shù):" + total);
        // 獲取列表
        orderDocs.getContent().forEach(System.out::println);
    }

聚合查詢(查詢最大,最小,平均,和等數(shù)據(jù))

{
  "aggs":{ 					
    "statsAmount":{ 		
      "stats":{ 				
        "field":"amount" 	
      }
    }
  }
}

該語句在java中的寫法:

     public void aggregation(){
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        
        builder.addAggregation(AggregationBuilders.max("maxAmount").field("amount"));
        // 聚合查詢
        AggregatedPage<OrderDoc> orderDocs = elasticsearchTemplate.queryForPage(
                builder.build(),
                OrderDoc.class
        );

        // 獲取條數(shù)
        long total = orderDocs.getTotalElements();
        System.out.println("總條數(shù):" + total);
        // 獲取列表
        orderDocs.getContent().forEach(System.out::println);

        // 獲取聚合結(jié)果
        Map<String, Aggregation> asMap = orderDocs.getAggregations().getAsMap();
        asMap.entrySet().forEach(aggregationEntry -> {
            //聚合名字
            String aggName = aggregationEntry.getKey();
            Aggregation aggregation = aggregationEntry.getValue();
            System.out.println("聚合名字 = "+aggName);
            if(aggregation instanceof ParsedLongTerms){
                //對(duì)應(yīng)terms聚合
                ParsedLongTerms agg = (ParsedLongTerms) aggregation;
                agg.getBuckets().forEach(bucket->{
                    String key = bucket.getKeyAsString();
                    long docCount = bucket.getDocCount();
                    System.out.println("key = "+key +" ; docCount = "+docCount);
                });
            }
            if(aggregation instanceof ParsedStats){
                //對(duì)應(yīng)stats聚合
                ParsedStats agg = (ParsedStats) aggregation;
                System.out.println(agg.getAvg());
                System.out.println(agg.getMax());
                System.out.println(agg.getCount());
                System.out.println(agg.getSum());
                System.out.println(agg.getMin());
            }
            if(aggregation instanceof ParsedSum){
                //對(duì)應(yīng)sum聚合
                ParsedSum agg = (ParsedSum) aggregation;
                System.out.println(agg.getValue());
            }
        });
    }

總結(jié)

以上就是springboot整合es的一些簡(jiǎn)單操作。

這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

柯坪县| 贵州省| 三明市| 扎兰屯市| 无极县| 潼南县| 扬州市| 保定市| 益阳市| 永济市| 遵义市| 乐山市| 正宁县| 商洛市| 宿松县| 运城市| 汉沽区| 楚雄市| 凉城县| 湖南省| 浮山县| 乌恰县| 临沭县| 什邡市| 广东省| 灵寿县| 贺州市| 拜城县| 芒康县| 阿勒泰市| 合肥市| 青铜峡市| 瓮安县| 邯郸市| 丰顺县| 进贤县| 华阴市| 邓州市| 土默特左旗| 金沙县| 青河县|