02ES基礎操作


IK分詞器插件

什么是IK分詞器?

分詞:即把一段中文或者別的划分成一個個的關鍵字,我們在搜索時候會把自己的信息進行分詞,會把數據庫中或者索引庫中的數據進行分詞,然后進行一個匹配操作,默認的中文分詞是將每個字看成一個詞,比如 “我愛狂神” 會被分為"我","愛","狂","神",這顯然是不符合要求的,所以我們需要安裝中文分詞器ik來解決這個問題。

如果要使用中文,建議使用ik分詞器!

IK提供了兩個分詞算法:ik_smart 和 ik_max_word,其中 ik_smart 為最少切分,ik_max_word為最細粒度划分!一會我們測試!

安裝步驟

1、下載ik分詞器的包,Github地址:https://github.com/medcl/elasticsearch-analysis-ik/ (版本要對應)

2、下載后解壓,並將目錄拷貝到ElasticSearch根目錄下的 plugins 目錄中。

b63eT1.png

3、重新啟動 ElasticSearch 服務,在啟動過程中,你可以看到正在加載"analysis-ik"插件的提示信息, 服務啟動后,在命令行運行 elasticsearch-plugin list 命令,確認 ik 插件安裝成功。

b63B6g.png

b634cF.png

4、在 kibana 中測試 ik 分詞器,並就相關分詞結果和 icu 分詞器進行對比。

ik_smart : 粗粒度分詞,優先匹配最長詞,只有1個詞!

b6JvcT.png

ik_max_word : 細粒度分詞,會窮盡一個語句中所有分詞可能,測試!

b6Y9HJ.png

5、我們輸入超級喜歡狂神說!發現狂神說被切分了

b6YDCq.png

如果我們想讓系統識別“狂神說”是一個詞,需要編輯自定義詞庫。

步驟:

(1)進入elasticsearch/plugins/ik/config目錄

(2)新建一個my.dic文件,編輯內容:

狂神說

(3)修改IKAnalyzer.cfg.xml(在ik/config目錄下)

<?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,再次測試!

發現監視了我們自己寫的規則文件:

b6tBee.png

再次測試,發現狂神說變成了一個詞:

b6tOyT.png

到了這里,我們就明白了分詞器的基本規則和使用了!

Rest風格說明

一種軟件架構風格,而不是標准,只是提供了一組設計原則和約束條件。它主要用於客戶端和服務器交互類的軟件。基於這個風格設計的軟件可以更簡潔,更有層次,更易於實現緩存等機制。

基本Rest命令說明:

method url地址 描述
PUT localhost:9200/索引名稱/類型名稱/文檔id 創建文檔(指定文檔id)
POST localhost:9200/索引名稱/類型名稱 創建文檔(隨機文檔id)
POST localhost:9200/索引名稱/類型名稱/文檔id/_update 修改文檔
DELETE localhost:9200/索引名稱/類型名稱/文檔id 刪除文檔
GET localhost:9200/索引名稱/類型名稱/文檔id 查詢文檔通過文檔id
POST localhost:9200/索引名稱/類型名稱/_search 查詢所有數據

關於索引的基本操作

基礎測試(創建索引)

1、首先我們瀏覽器 http://localhost:5601/ 進入 kibana里的Console

2、首先讓我們在 Console 中輸入 :

// 命令解釋
// PUT 創建命令 test1 索引 type1 類型 1 id
PUT /test1/type1/1
{
"name":"狂神說", // 屬性
"age":16 // 屬性
}

返回結果 (是以REST ful 風格返回的 ):

// 警告信息:不支持在文檔索引請求中指定類型
// 而是使用無類型的端點(/{index}/_doc/{id}, /{index}/_doc,或 /{index}/_create/{id})。
#! Deprecation: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).
{
  "_index" : "test1", 	// 索引
  "_type" : "type1", 	// 類型
  "_id" : "1",			// id
  "_version" : 1,		// 版本
  "result" : "created",	// 操作類型
  "_shards" : {			// 分片信息
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

b2m5lQ.png

完成了自動增加了索引!數據也成功的添加了,這就是我說大家在初期可以把它當作數據庫學習的原因!

b2nAfO.png

2、那么 name 這個字段用不用指定類型呢。畢竟我們關系型數據庫 是需要指定類型的啊 !

4、指定字段類型

PUT /test2
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "age":{
        "type": "long"
      },
      "birthday":{
        "type": "date"
      }
    }
  }
}

輸出:

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

b2KdYV.png

5、查看一下索引字段

GET test2

輸出:

{
  "test2" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "birthday" : {
          "type" : "date"
        },
        "name" : {
          "type" : "text"
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1646752424929",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "ChJG56WlTU-ozPxdHk8Rpg",
        "version" : {
          "created" : "7060199"
        },
        "provided_name" : "test2"
      }
    }
  }
}

b2MYcD.png

6、我們看上列中 字段類型是我自己定義的 那么 我們不定義類型 會是什么情況呢?

PUT /test3/_doc/1
{
  "name":"狂神說",
  "age":13,
  "birth":"1997-01-05"
}

輸出:

{
  "_index" : "test3",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

b2QrZ9.png

查看一下test3索引:

GET test3

返回結果:

{
  "test3" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "birth" : {
          "type" : "date"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "creation_date" : "1646752907193",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "N2PiarItRnKPqizVEuvolg",
        "version" : {
          "created" : "7060199"
        },
        "provided_name" : "test3"
      }
    }
  }
}

b2QqRf.png

我們看上列沒有給字段指定類型那么es就會默認給我配置字段類型!

對比關系型數據庫 :

PUT test1/type1/1 : 索引test1相當於關系型數據庫的庫,類型type1就相當於表 ,1 代表數據中的主 鍵 id

這里需要補充的是 ,在elastisearch5版本前,一個索引下可以創建多個類型,但是在elastisearch5后, 一個索引只能對應一個類型,而id相當於關系型數據庫的主鍵id若果不指定就會默認生成一個20位的 uuid,屬性相當關系型數據庫的column(列)。

而結果中的 result 則是操作類型,現在是 created ,表示第一次創建。如果再次點擊執行該命令那么 result 則會是 updated ,我們細心則會發現 _version 開始是1,現在你每點擊一次就會增加一次。表示 第幾次更改。

7、我們在來學一條命令 (elasticsearch 中的索引的情況) :

GET _cat/indices?v

返回結果:查看我們所有索引的狀態健康情況 分片,數據儲存大小等等。

b2lOt1.png

修改 提交還是使用PUT即可!然后覆蓋!最新辦法!

曾經!

當執行 PUT 命令時,如果數據不存在,則新增該條數據,如果數據存在則修改該條數據。

b21T8P.png

麻煩的是 原數據你還要重寫一遍要 這不符合我們規矩。

現在的!

我們使用 POST 命令,在 id 后面跟 _update ,要修改的內容放到 doc 文檔(屬性)中即可。

b238VH.png

刪除索引!

通過 DELETE 命令實現刪除、根據你的請求來判斷是刪除索引還是刪除文檔記錄!

使用 RESTFUL 風格是我們ES推薦大家使用的!

 DELETE /test1

返回:

{
  "acknowledged" : true // 表示刪除成功!
}

關於文檔的基本操作

創建數據PUT

// 第一條數據:
PUT /kuangshen/user/1
{
  "name":"狂神說",
  "age":23,
  "desc":"一段操作猛如虎,一看工資2500",
  "tags":["技術宅","暖男","直男"]
}
// 第二條數據:
PUT /kuangshen/user/2
{
  "name":"張三",
  "age":3,
  "desc":"法外狂徒",
  "tags":["交友","旅游","渣男"]
}
// 第三條數據:
PUT /kuangshen/user/3
{
  "name":"李四",
  "age":30,
  "desc":"mmp,不知道怎么形容",
  "tags":["靚女","旅游","唱歌"]
}

查看下數據:

bfMCIs.png

注意⚠ :當執行 命令時,如果數據不存在,則新增該條數據,如果數據存在則修改該條數據。

咱們通過 GET 命令查詢一下 :

GET /kuangshen/user/1

返回結果:

#! Deprecation: [types removal] Specifying types in document get requests is deprecated, use the /{index}/_doc/{id} endpoint instead.
{
  "_index" : "kuangshen",
  "_type" : "user",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "狂神說",
    "age" : 23,
    "desc" : "一段操作猛如虎,一看工資2500",
    "tags" : [
      "技術宅",
      "暖男",
      "直男"
    ]
  }
}

如果你想更新數據 可以覆蓋這條數據 :

PUT /kuangshen/user/3
{
  "name":"李四233",
  "age":30,
  "desc":"mmp,不知道怎么形容",
  "tags":["靚女","旅游","唱歌"]
}

返回結果:

#! Deprecation: [types removal] Specifying types in document index requests is deprecated, use the typeless endpoints instead (/{index}/_doc/{id}, /{index}/_doc, or /{index}/_create/{id}).
{
  "_index" : "kuangshen",
  "_type" : "user",
  "_id" : "3",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

已經修改了 那么 PUT 可以更新數據。但是,麻煩的是 原數據你還要重寫一遍要 這不符合我們規矩。

更新數據 POST

我們使用 POST 命令,在 id 后面跟 _update ,要修改的內容放到 doc 文檔(屬性)中即可。

POST /kuangshen/user/1/_update
{
  "doc":{
    "name":"狂神說Java"
  }
}

返回結果:

#! Deprecation: [types removal] Specifying types in document update requests is deprecated, use the endpoint /{index}/_update/{id} instead.
{
  "_index" : "kuangshen",
  "_type" : "user",
  "_id" : "1",
  "_version" : 4,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 6,
  "_primary_term" : 1
}

條件查詢_search?q=

簡單的查詢,我們上面已經不知不覺的使用熟悉了:

GET /kuangshen/user/1

我們來學習下條件查詢 _search?q=

GET /kuangshen/user/_search?q=name:狂神說

通過 _serarch?q=name:狂神說 查詢條件是name屬性有狂神說的那些數據。

別忘 了 _search 和 q 屬性中間的分隔符 ? 。

返回結果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 17,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.7796593,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.7796593,
        "_source" : {
          "name" : "狂神說Java",
          "age" : 23,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        }
      }
    ]
  }
}

我們看一下結果 返回並不是 數據本身,是給我們了一個 hits ,還有 **_score ** 得分,就是根據算法算出的查詢條件匹配度的得分。

構建查詢

GET kuangshen/user/_search
{
  "query": {
    "match": {
      "name": "狂神"
    }
  }
}

上例,查詢條件是一步步構建出來的,將查詢條件添加到 match 中即可。返回結果還是一樣的:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.489748,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.489748,
        "_source" : {
          "name" : "狂神說Java",
          "age" : 23,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        }
      }
    ]
  }
}

除此之外,我們還可以查詢全部:

GET kuangshen/user/_search	#這是一個查詢但是沒有條件
{
  "query": {
    "match_all": {}
  }
}

match_all的值為空,表示沒有查詢條件,就像select * from table_name一樣。

返回結果:全部查詢出來了!

如果有個需求,我們僅是需要查看 name 和 desc 兩個屬性,其他的不要怎么辦?

GET kuangshen/user/_search
{
  "query": {
    "match": {
      "name": "狂神"
    }
  },
  "_source": ["name","desc"]
}

如上例所示,在查詢中,通過 _source 來控制僅返回 name 和 age 屬性。

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.00541,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.00541,
        "_source" : {
          "name" : "狂神說Java",
          "desc" : "一段操作猛如虎,一看工資2500"
        }
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "4",
        "_score" : 0.90396726,
        "_source" : {
          "name" : "狂神說前端",
          "desc" : "一段操作猛如虎,一看工資2500"
        }
      }
    ]
  }
}

一般的,我們推薦使用構建查詢,以后在與程序交互時的查詢等也是使用構建查詢方式處理查詢條件, 因為該方 式可以構建更加復雜的查詢條件,也更加一目了然

排序查詢

我們說到排序 有人就會想到:正序 或 倒序 那么我們先來倒序:

GET kuangshen/user/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "desc"
      }
    }
  ]
}

上例,在條件查詢的基礎上,我們又通過 sort 來做排序,排序對象是 age , order 是 desc 降序。

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "3",
        "_score" : null,
        "_source" : {
          "name" : "李四233",
          "age" : 30,
          "desc" : "mmp,不知道怎么形容",
          "tags" : [
            "靚女",
            "旅游",
            "唱歌"
          ]
        },
        "sort" : [
          30
        ]
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "name" : "狂神說Java",
          "age" : 23,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        },
        "sort" : [
          23
        ]
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "name" : "張三",
          "age" : 3,
          "desc" : "法外狂徒",
          "tags" : [
            "交友",
            "旅游",
            "渣男"
          ]
        },
        "sort" : [
          3
        ]
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "4",
        "_score" : null,
        "_source" : {
          "name" : "狂神說前端",
          "age" : 3,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        },
        "sort" : [
          3
        ]
      }
    ]
  }
}

正序,就是 desc 換成了 asc

GET kuangshen/user/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ]
}

注意:在排序的過程中,只能使用可排序的屬性進行排序。那么可以排序的屬性有哪些呢?

  • 數字
  • 日期
  • ID

其他都不行!

分頁查詢

GET kuangshen/user/_search
{
  "query": {
    "match_all": {}
  },
  "sort": [
    {
      "age": {
        "order": "asc"
      }
    }
  ],
  "from": 0,	# 從第n條開始
  "size": 1		# 返回n條數據
}

返回結果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "name" : "張三",
          "age" : 3,
          "desc" : "法外狂徒",
          "tags" : [
            "交友",
            "旅游",
            "渣男"
          ]
        },
        "sort" : [
          3
        ]
      }
    ]
  }
}

就返回了一條數據 是從第0條開始的返回一條數據 。可以再測試!

學到這里,我們也可以看到,我們的查詢條件越來越多,開始僅是簡單查詢,慢慢增加條件查詢,增加 排序,對返回 結果進行限制。所以,我們可以說:對於elasticsearch來說,所有的查詢條件都是可插拔的,彼此之間可分割。比如說,我們在查詢中,僅對返回結果進行限制:

GET kuangshen/user/_search
{
  "query": {
    "match_all": {}
  },
  "from": 0,	# 從第n條開始
  "size": 1		# 返回n條數據
}

布爾查詢

must (and)

我要查詢所有 name 屬性為“ 狂神說 “的數據,並且年齡為3的!

GET kuangshen/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "狂神說"
          }
        },
        {
          "match": {
            "age": 3
          }
        }
      ]
    }
  }
}

我們通過在 bool 屬性內使用 must 來作為查詢條件!看結果,是不是 有點像 and 的感覺,里面的條件需要都滿足!

should (or)

那么我要查詢name為狂神說 或 age 為 3 的呢?

GET kuangshen/user/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "name": "狂神說"
          }
        },
        {
          "match": {
            "age": 3
          }
        }
      ]
    }
  }
}

返回結果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 2.3559508,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "4",
        "_score" : 2.3559508,
        "_source" : {
          "name" : "狂神說前端",
          "age" : 3,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        }
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.5081149,
        "_source" : {
          "name" : "狂神說Java",
          "age" : 23,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        }
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "張三",
          "age" : 3,
          "desc" : "法外狂徒",
          "tags" : [
            "交友",
            "旅游",
            "渣男"
          ]
        }
      }
    ]
  }
}

我們的返回結果 是不是 出現了一個 age : 23的。是不是有點像 or

must_not (not)

我想要查詢 年齡不是 3 的數據

GET kuangshen/user/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "match": {
            "age": 3
          }
        }
      ]
    }
  }
}

Fitter

我要查詢 name 為狂神 的,age大於10的數據

GET kuangshen/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "狂神"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gt": 10
          }
        }
      }
    }
  }
}

這里就用到了 filter 條件過濾查詢,過濾條件的范圍用 range 表示, gt 表示大於,大於多少呢?是10。

其余操作如下 :

  • gt 表示大於
  • gte 表示大於等於
  • lt 表示小於
  • lte 表示小於等於

要查詢 name 是 狂神, age 在 1~30 之間的怎么查?

GET kuangshen/user/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "狂神"
          }
        }
      ],
      "filter": {
        "range": {
          "age": {
            "gt": 1,
            "lt": 30
          }
        }
      }
    }
  }
}

短語檢索

我要查詢 tags為男的數據

GET kuangshen/user/_search
{
  "query": {
    "match": {
      "tags": "男"
    }
  }
}

返回了所有標簽中帶 男 的記錄!

既然按照標簽檢索,那么,能不能寫多個標簽呢?又該怎么寫呢?

GET kuangshen/user/_search
{
  "query": {
    "match": {
      "tags": "男 技術"
    }
  }
}

返回:只要含有這個標簽滿足一個就給我返回這個數據了。

term查詢精確查詢

term 查詢是直接通過倒排索引指定的 詞條,也就是精確查找。

term和match的區別:

  • match是經過分析(analyer)的,也就是說,文檔是先被分析器處理了,根據不同的分析器,分析出的結果也會不同,才會根據分詞 結果進行匹配。
  • term是不經過分詞的,直接去倒排索引查找精確的值。

總結:

1、match的查詢條件會分詞,假如查詢字段是text,即可分詞查詢,假如查詢字段是keyword,那必須查詢條件是keyword才可被查到

2、term的查詢條件不會分詞的,必須是倒排索引的詞匯,才可查詢。而keyword類型的字段的值一定在倒排索引的詞匯中。

注意 ⚠ :我們現在 用的es7版本 所以我們用 mappings properties 去給多個字段(fields)指定類型的時候,不能給我們的 索引制定類型:

PUT testdb
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "desc":{
        "type": "keyword"
      }
    }
  }
}
// 插入數據
PUT testdb/_doc/1
{
  "name":"狂神說Java name",
  "desc":"狂神說Java desc"
}

PUT testdb/_doc/2
{
  "name":"狂神說Java name",
  "desc":"狂神說Java desc2"
}

上述中testdb索引中,字段name在被查詢時會被分析器進行分析后匹配查詢。而屬於keyword類型不會被分析器處理。

我們來驗證一下:

GET _analyze
{
  "analyzer": "keyword",
  "text":"狂神說Java name"
}

結果:

{
  "tokens" : [
    {
      "token" : "狂神說Java name",
      "start_offset" : 0,
      "end_offset" : 12,
      "type" : "word",
      "position" : 0
    }
  ]
}

是不是沒有被分析啊。就是簡單的一個字符串啊。再測試

GET _analyze
{
  "analyzer": "standard",
  "text":"狂神說Java name"
}

結果:

{
  "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" : "java",
      "start_offset" : 3,
      "end_offset" : 7,
      "type" : "<ALPHANUM>",
      "position" : 3
    },
    {
      "token" : "name",
      "start_offset" : 8,
      "end_offset" : 12,
      "type" : "<ALPHANUM>",
      "position" : 4
    }
  ]
}

那么我們看一下 字符串是不是被分析了啊。

總結:keyword 字段類型不會被分析器分析!

現在我們來查詢一下:

GET testdb/_search	// text 會被分析器分析 為 狂 神 說 Java name,倒排索引的文檔中沒有 狂神說 ,所以查詢不到
{					// 假如只搜 name:狂,可以搜到數據
  "query": {
    "term": {
      "name": {
        "value": "狂神說"
      }
    }
  }
}

GET testdb/_search	// keyword 不會被分析,倒排索引的文檔中有 狂神說Java desc,所以能被查到
{
  "query": {
    "term": {
      "desc": {
        "value": "狂神說Java desc"
      }
    }
  }
}

查找多個精確值(terms)

官網地址:https://www.elastic.co/guide/cn/elasticsearch/guide/current/_finding_multiple_exact_values.html

PUT testdb/_doc/3
{
  "t1":"22",
  "t2":"2022-3-12"
}


PUT testdb/_doc/4
{
  "t1":"33",
  "t2":"2022-4-12"
}

# 查詢 精確查找多個值
GET  testdb/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "term": {
            "t1": "22"
          }
        },
        {
          "term": {
            "t1":"33"
          }
        }
      ]
    }
  }
}

除了bool查詢之外:

GET  testdb/_search
{
  "query": {
    "terms": {
      "t1": [
        "22",
        "33"
      ]
    }
  }
}

高亮顯示

GET kuangshen/user/_search
{
  "query": {
    "match": {
      "name": "狂神"
    }
  },
  "highlight": {
    "fields": {
      "name":{}
    }
  }
}

返回結果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.00541,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.00541,
        "_source" : {
          "name" : "狂神說Java",
          "age" : 23,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        },
        "highlight" : {
          "name" : [
            "<em>狂</em><em>神</em>說Java"
          ]
        }
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "4",
        "_score" : 0.90396726,
        "_source" : {
          "name" : "狂神說前端",
          "age" : 3,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        },
        "highlight" : {
          "name" : [
            "<em>狂</em><em>神</em>說前端"
          ]
        }
      }
    ]
  }
}

我們可以看到已經幫我們加上了一個<em>標簽

<em>狂</em><em>神</em>說前端

"highlight" : {
          "name" : [
            "<em>狂</em><em>神</em>說前端"
          ]
        }

這是es幫我們加的標簽。那我也可以自己自定義樣式

GET kuangshen/user/_search
{
  "query": {
    "match": {
      "name": "狂神"
    }
  },
  "highlight": {
    "pre_tags": "<p class='key' stype='color:red'>", 
    "post_tags": "</p>", 
    "fields": {
      "name":{}
    }
  }
}

結果:

#! Deprecation: [types removal] Specifying types in search requests is deprecated.
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 1.00541,
    "hits" : [
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "1",
        "_score" : 1.00541,
        "_source" : {
          "name" : "狂神說Java",
          "age" : 23,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        },
        "highlight" : {
          "name" : [
            "<p class='key' stype='color:red'>狂</p><p class='key' stype='color:red'>神</p>說Java"
          ]
        }
      },
      {
        "_index" : "kuangshen",
        "_type" : "user",
        "_id" : "4",
        "_score" : 0.90396726,
        "_source" : {
          "name" : "狂神說前端",
          "age" : 3,
          "desc" : "一段操作猛如虎,一看工資2500",
          "tags" : [
            "技術宅",
            "暖男",
            "直男"
          ]
        },
        "highlight" : {
          "name" : [
            "<p class='key' stype='color:red'>狂</p><p class='key' stype='color:red'>神</p>說前端"
          ]
        }
      }
    ]
  }
}

需要注意的是:自定義標簽中屬性或樣式中的逗號一律用英文狀態的單引號表示,應該與外部 es 語法 的雙引號區分開。

說明:Deprecation

注意 elasticsearch 在第一個版本的開始 每個文檔都儲存在一個索引中,並分配一個 映射類型,映射類型用於表示被索引的文檔或者實體的類型,這樣帶來了一些問題, 導致后來在 elasticsearch6.0.0 版本中 一個文檔只能包含一個映射類型,而在 7.0.0 中,映射類型則將被棄用,到了 8.0.0 中則將完全被刪除。

只要記得,一個索引下面只能創建一個類型就行了,其中各字段都具有唯一性,如果在創建映射的時候,如果沒有指定文檔類型,那么該索引的默認索引類型是 _doc ,不指定文檔id則會內部幫我們生成一個id字符串。

API創建索引及文檔

找文檔

網上的es教程大都十分老舊,而且es的版本眾多,個別版本的差異還較大,另外es本身提供多種api,導致許多文章各種亂七八糟實例!所以后面直接放棄,從官網尋找方案,這里我使用elasticsearch最新的 7.6.1版本來講解:

1、進入es的官網指導文檔 https://www.elastic.co/guide/index.html

2、找到 Elasticsearch Clients(這個就是客戶端api文檔)

bqjnnH.png

3、我們使用java rest風格api,大家可以根據自己的版本選擇特定的other versions。

bqj2DJ.png

4、rest又分為high level和low level,我們直接選擇high level下面的 Getting started

bqjXVA.png

5、向下閱讀找到Maven依賴和基本配置!

bqvPKg.png

Java REST Client 說明

Java REST Client 有兩種風格:

Java Low Level REST Client :用於Elasticsearch的官方低級客戶端。它允許通過http與Elasticsearch集群通信。將請求編排和響應反編排留給用戶自己處理。它兼容所有的Elasticsearch版本。(PS:學過WebService的話,對編排與反編排這個概念應該不陌生。可以理解為對請求參數的封裝,以及對響應結果的解析)

Java High Level REST Client :用於Elasticsearch的官方高級客戶端。它是基於低級客戶端的,它提供很多API,並負責請求的編排與響應的反編排。(PS:就好比是,一個是傳自己拼接好的字符串,並且自己解析返回的結果;而另一個是傳對象,返回的結果也已經封裝好了,直接是對象,更加規范了參數的名稱以及格式,更加面對對象一點)

(PS:所謂低級與高級,我覺得一個很形象的比喻是,面向過程編程與面向對象編程)

網上很多教程比較老舊,都是使用TransportClient操作的,在 Elasticsearch 7.0 中不建議使用 TransportClient,並且在8.0中會完全刪除TransportClient。因此,官方更建議我們用Java High Level REST Client,它執行HTTP請求,而不是序列號的Java請求。既然如此,這里我們就直接用高級了。

配置基本項目依賴

1、新建一個springboot(2.2.5版)項目 edgar-es-api,導入web依賴即可!

2、配置es的依賴!

<properties>
	<java.version>1.8</java.version>
	<!-- 這里SpringBoot默認配置的版本不匹配,我們需要自己配置版本! -->
	<elasticsearch.version>7.6.1</elasticsearch.version>
</properties>

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

3、繼續閱讀文檔到Initialization ,我們看到需要構建RestHighLevelClient對象;

RestHighLevelClient client = new RestHighLevelClient(
		RestClient.builder(
				new HttpHost("localhost", 9200, "http"),
				new HttpHost("localhost", 9201, "http"))); // 構建客戶端對象
// 操作....
// 高級客戶端內部會創建低級客戶端用於基於提供的builder執行請求。低級客戶端維護一個連接池,
//並啟動一些線程,因此當你用完以后應該關閉高級客戶端,並且在內部它將會關閉低級客戶端,以釋放這
//些資源。關閉客戶端可以使用close()方法:
client.close(); // 關閉

4、我們編寫一個配置類,提供這個bean來進行操作

package com.edgar.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ElasticsearchClientConfig {

    @Bean
    public RestHighLevelClient restHighLevelClient(){
        RestHighLevelClient client = new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost("localhost", 9200, "http")));
        return client;
    }
}

常用方法工具類封裝

package com.edgar.utils;

import com.alibaba.fastjson.JSON;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class EsUtils<T> {
    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;

    /**
     * 判斷索引是否存在
     *
     * @param index
     * @return
     * @throws IOException
     */
    public boolean existsIndex(String index) throws IOException {
        GetIndexRequest request = new GetIndexRequest(index);
        boolean exists = client.indices().exists(request,
                RequestOptions.DEFAULT);
        return exists;
    }

    /**
     * 創建索引
     *
     * @param index
     * @throws IOException
     */
    public boolean createIndex(String index) throws IOException {
        CreateIndexRequest request = new CreateIndexRequest(index);
        CreateIndexResponse createIndexResponse
                = client.indices().create(request, RequestOptions.DEFAULT);
        return createIndexResponse.isAcknowledged();
    }

    /**
     * 刪除索引
     *
     * @param index
     * @return
     * @throws IOException
     */
    public boolean deleteIndex(String index) throws IOException {
        DeleteIndexRequest deleteIndexRequest = new
                DeleteIndexRequest(index);
        AcknowledgedResponse response =
                client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    /**
     * 判斷某索引下文檔id是否存在
     *
     * @param index
     * @param id
     * @return
     * @throws IOException
     */
    public boolean docExists(String index, String id) throws IOException {
        GetRequest getRequest = new GetRequest(index, id);
        //只判斷索引是否存在不需要獲取_source
        getRequest.fetchSourceContext(new FetchSourceContext(false));
        getRequest.storedFields("_none_");
        boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
        return exists;
    }

    /**
     * 添加文檔記錄
     *
     * @param index
     * @param id
     * @param t     要添加的數據實體類
     * @return
     * @throws IOException
     */
    public boolean addDoc(String index, String id, T t) throws IOException {
        IndexRequest request = new IndexRequest(index);
        request.id(id);
        //timeout
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
        request.source(JSON.toJSONString(t), XContentType.JSON);
        IndexResponse indexResponse = client.index(request,
                RequestOptions.DEFAULT);
        RestStatus Status = indexResponse.status();
        return Status == RestStatus.OK || Status == RestStatus.CREATED;
    }

    /**
     * 根據id來獲取記錄
     *
     * @param index
     * @param id
     * @return
     * @throws IOException
     */
    public GetResponse getDoc(String index, String id) throws IOException {
        GetRequest request = new GetRequest(index, id);
        GetResponse getResponse = client.get(request,
                RequestOptions.DEFAULT);
        return getResponse;
    }

    /**
     * 批量添加文檔記錄
     * 沒有設置id ES會自動生成一個,如果要設置 IndexRequest的對象.id()即可
     *
     * @param index
     * @param list
     * @return
     * @throws IOException
     */
    public boolean bulkAdd(String index, List<T> list) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        //timeout
        bulkRequest.timeout(TimeValue.timeValueMinutes(2));
        bulkRequest.timeout("2m");
        for (int i = 0; i < list.size(); i++) {
            bulkRequest.add(new IndexRequest(index)
                    .source(JSON.toJSONString(list.get(i))));
        }
        BulkResponse bulkResponse = client.bulk(bulkRequest,
                RequestOptions.DEFAULT);
        return !bulkResponse.hasFailures();
    }
    
    /**
     * 批量刪除和更新就不寫了可根據上面幾個方法來寫
     */
    
    /**
     * 更新文檔記錄
     *
     * @param index
     * @param id
     * @param t
     * @return
     * @throws IOException
     */
    public boolean updateDoc(String index, String id, T t) throws IOException {
        UpdateRequest request = new UpdateRequest(index, id);
        request.doc(JSON.toJSONString(t));
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
        UpdateResponse updateResponse = client.update(
                request, RequestOptions.DEFAULT);
        return updateResponse.status() == RestStatus.OK;
    }

    /**
     * 刪除文檔記錄
     *
     * @param index
     * @param id
     * @return
     * @throws IOException
     */
    public boolean deleteDoc(String index, String id) throws IOException {
        DeleteRequest request = new DeleteRequest(index, id);
        //timeout
        request.timeout(TimeValue.timeValueSeconds(1));
        request.timeout("1s");
        DeleteResponse deleteResponse = client.delete(
                request, RequestOptions.DEFAULT);
        return deleteResponse.status() == RestStatus.OK;
    }

    /**
     * 根據某字段來搜索
     *
     * @param index
     * @param field
     * @param key   要收搜的關鍵字
     * @throws IOException
     */
    public void search(String index, String field, String key, Integer
            from, Integer size) throws IOException {
        SearchRequest searchRequest = new SearchRequest(index);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.termQuery(field, key));
        //控制搜素
        sourceBuilder.from(from);
        sourceBuilder.size(size);
        //最大搜索時間。
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(sourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest,
                RequestOptions.DEFAULT);
        System.out.println(JSON.toJSONString(searchResponse.getHits()));
    }
}

APIs 測試

測試創建索引:

// 測試索引的創建  Request
@Test
void testCreateIndex() throws IOException {
    // 1、創建索引的請求
    CreateIndexRequest request = new CreateIndexRequest("kuang_index");
    // 2、客戶端執行請求 IndicesClient,請求后獲得響應
    CreateIndexResponse createIndexResponse =
            client.indices().create(request, RequestOptions.DEFAULT);

    System.out.println(createIndexResponse);
}

測試獲取索引:

// 測試獲取索引,判斷其是否存在
@Test
void testExistIndex() throws IOException {
    GetIndexRequest request = new GetIndexRequest("kuang_index2");
    boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
    System.out.println(exists);
}

測試刪除索引:

// 測試刪除索引
@Test
void testDeleteIndex() throws IOException {
    DeleteIndexRequest request = new DeleteIndexRequest("kuang_index");
    AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
    System.out.println(delete.isAcknowledged());
}

測試添加文檔記錄:

創建一個實體類User

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
public class User {

    private String name;
    private int age;
}

測試添加文檔記錄

// 測試添加文檔
@Test
void testAddDocument() throws IOException {
    // 創建對象
    User user = new User("狂神說", 3);
    // 創建請求
    IndexRequest request = new IndexRequest("kuang_index");

    // 規則 put /kuang_index/_doc/1
    request.id("1");
    request.timeout(TimeValue.timeValueSeconds(1));

    // 將我們的數據放入請求 json
    request.source(JSON.toJSONString(user), XContentType.JSON);

    // 客戶端發送請求,獲取響應的結果
    IndexResponse indexResponse = client.index(request, RequestOptions.DEFAULT);

    System.out.println(indexResponse.toString());
    System.out.println(indexResponse.status()); // 對應我們命令返回的狀態 CREATED
}

測試:判斷某索引下文檔id是否存在

// 獲取文檔,判斷是否存在 get /kuang_index/_doc/1
@Test
void testIsExists() throws IOException {
    GetRequest getRequest = new GetRequest("kuang_index", "1");
    // 不獲取返回的 _source的上下文了
    getRequest.fetchSourceContext(new FetchSourceContext(false));
    getRequest.storedFields("_none_");
    boolean exists = client.exists(getRequest, RequestOptions.DEFAULT);
    System.out.println(exists);
}

測試:根據id獲取記錄

// 獲取文檔的信息
@Test
void testGetDocument() throws IOException {
    GetRequest getRequest = new GetRequest("kuang_index", "1");
    GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
    System.out.println(getResponse.getSourceAsString()); // 打印文檔的內容
    System.out.println(getResponse); // 返回的全部內容和命令是一樣的
}

測試:更新文檔記錄

// 更新文檔的信息
@Test
void testUpdateRequest() throws IOException {
    UpdateRequest updateRequest = new UpdateRequest("kuang_index", "1");
    updateRequest.timeout("1s");

    User user = new User("狂神說Java", 18);
    updateRequest.doc(JSON.toJSONString(user),XContentType.JSON);

    UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
    System.out.println(updateResponse.status());
}

測試:刪除文檔記錄

// 刪除文檔記錄
@Test
void testDeleteRequest() throws IOException {
    DeleteRequest deleteRequest = new DeleteRequest("kuang_index", "1");
    deleteRequest.timeout("1s");

    DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
    System.out.println(deleteResponse.status());
}

測試:批量添加文檔

// 特殊的,真實的項目一般都會批量插入數據!
@Test
void testBulkRequest() throws IOException {
    BulkRequest bulkRequest = new BulkRequest();
    bulkRequest.timeout("10s");

    ArrayList<User> users = new ArrayList<>();
    users.add(new User("kuangshen1",3));
    users.add(new User("kuangshen1",3));
    users.add(new User("kuangshen1",3));
    users.add(new User("qinjiang1",3));
    users.add(new User("qinjiang1",3));
    users.add(new User("qinjiang1",3));

    // 批處理請求
    for (int i = 0; i < users.size(); i++) {
        // 批量更新和批量刪除,就在這里修改對應的請求就可以了
        bulkRequest.add(
                new IndexRequest("kuang_index")
                .source(JSON.toJSONString(users.get(i)),XContentType.JSON));
    }

    BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
    System.out.println(bulkResponse.hasFailures()); // 是否失敗,返回 false 代表成功!
}

查詢測試:

// 查詢
// SearchRequest 搜索請求
// SearchSourceBuilder 條件構造
// HighlightBuilder 構建高亮
// TermQueryBuilder 精確查詢
// MatchAllQueryBuilder
// xxxQueryBuilder 對應我們剛才看到的所有命令!
@Test
void testSearch() throws IOException {
    SearchRequest searchRequest = new SearchRequest("kuang_index");
    // 構建搜索的條件
    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

    // 查詢條件,我們可以使用 QueryBuilders 工具類來實現
    // QueryBuilders.termQuery 精確
    // QueryBuilders.matchAllQuery() 匹配所有
    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "qinjiang1");
//        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
    sourceBuilder.query(termQueryBuilder);
    sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

    searchRequest.source(sourceBuilder);
    SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
    System.out.println(JSON.toJSONString(searchResponse.getHits()));
    System.out.println("=============================");
    for (SearchHit documentFields : searchResponse.getHits().getHits()) {
        System.out.println(documentFields.getSourceAsMap());
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM