Spring Cloud 学習ルート (10) - 分散検索 ElasticSeach の基礎

1. ESを初めて知る

(1) コンセプト:

ES はオープンソースの検索エンジンで、データ視覚化 [Kibana]、データ キャプチャ [Logstash、Beats] と組み合わされ、ELK (Elastic Stack) に統合されています。ELK はログ データ分析やリアルタイム監視などの分野で広く使用されています。はコアコンポーネントです。

(2) 機能:効率的なクエリ検索コンテンツ。

(3) 開発経緯:

1. 基礎となる実装は、Apache のトップ製品の 1 つである Java 言語検索エンジンのクラス ライブラリであるLuceneで、1999 年に DoungCutting によって開発されました。公式アドレス: https://lucene.apache.org/
Lucene の利点:拡張が容易 (二次開発)可能)、高パフォーマンス(逆インデックスに基づく)
Lucene の欠点: Java 開発のみに限定される、急峻な学習曲線、水平拡張をサポートしない

2. 2004 年、Shay Banon はLuceneに基づいてCompassを開発しました。

3. 2010 年、Shay Banon は Compass を書き換え、 Elasticsearch の
公式アドレスに名前を変更しました: https://www.elastic.co/cn/
ES の利点:

  • 分散サポート、水平拡張サポート
  • 任意の言語で呼び出すことができる RESTful インターフェイスを提供する

(4) 他の検索エンジンと比較したESの利点

検索エンジン技術の使用頻度に応じてランク付けされており、上位 3 つは次のとおりです。

  • ES: オープンソースの分散型検索エンジン (一般的に使用されています)
  • Splunk: 商用プロジェクト
  • Solr: Apache のオープンソース リソース エンジン (一般的に使用されます)

(5) 順方向インデックスと転置インデックス

1. 前方インデックス
従来のデータベース (MySQL など) は前方インデックスを使用します。

  • 項目ごとにコンテンツをクエリに一致させます
  • 一致しない場合は破棄し、一致する場合は結果セットに入れます。

2. 転置インデックス

ES は転置インデックスを使用します。

  • Document (ドキュメント):それぞれのデータがドキュメントです
  • 用語:文書を意味的に分割した単語

転置インデックスは、まずインデックスで使用されるフィールドを用語に分割し、それらを用語 ID キーと値のペア テーブルに保存します。分割された用語が同じである場合、現在のデータ行の ID のみが ID に記録されます。インデックステーブルフィールドの。

転置インデックスの一致するデータ順序:

  • 検索コンテンツの単語分割
  • 取得したエントリはエントリ リストに移動し、ID を照会します。
  • ドキュメント ID によるドキュメントのクエリ
  • データは結果セットに保存されます

(6) ESとMySQLの概念比較

  • ES はドキュメントストレージであり、データベース内の商品データや注文情報などです。
  • ドキュメントデータはjson形式にシリアル化され、elasticsearchに保存されます。

1.ES書類

{
	"id": 1,
	“title”: "小米手机",
	"price": 2499
}
{
	"id": 2,
	“title”: "华为手机",
	"price": 4699
}
{
	"id": 3,
	“title”: "华为小米充电器",
	"price": 49
}
{
	"id": 4,
	“title”: "小米手环",
	"price": 299
}

2. ES指数

インデックス(Index)とは、同じ種類の文書の集まりです(種類が同じかどうかは、文書の構造を見ることでわかります)。

3. MySQLとESの概念比較

  • 表: 索引—— 図書館の表のような文書の集合である索引 (表)
  • 行: ドキュメント—— ドキュメント。データベースの行 (行) に似たデータ行であり、ドキュメントは JSON 形式です。
  • 列: フィールド—— フィールド。データベースの列 (列) に似た、JSON ドキュメントの属性です。
  • スキーマ: マッピング- マッピングは、フィールド タイプの制約など、インデックス内のドキュメントの制約です。データベースのテーブル構造(スキーマ)と同様
  • SQL: DSL —— DSL は ES が提供する JSON 形式のリクエスト ステートメントであり、ES を実行して CRUD を実現するために使用されます。

4. アーキテクチャ

MySQL アーキテクチャ: データのセキュリティと一貫性を確保するためのトランザクション タイプの操作に優れています。(主に書き込み操作)
ES アーキテクチャ: 大量のデータの検索、分析、計算を得意とします。(主に読み取り操作)

(7) ESとkibanaのインストール

キバナをインストールする理由 ESの運用をkibanaが手伝ってくれるからです。

1. 単一の ES を展開する

(1) ネットワークを作成する

kibanaコンテナもデプロイする必要があるため、es コンテナと kibana コンテナを相互接続してネットワークを作成する必要があります。

docker network create es-net

ここに画像の説明を挿入
(2) 画像の読み込み

docker pull elasticsearch:7.12.1

ここに画像の説明を挿入
(3) ESを実行する

docker コマンドを実行してシングルポイント es をデプロイします。

# -e "cluster.name=es-docker-cluster:设置集群名称
# -e "ES_JAVA_OPTS=-Xms512m -Xmx512m": 设置堆内存大小
# -e "discovery.type=single-node": 配置部署类型为单点
# -v es-data:/usr/share/elasticsearch/data: ES数据挂载点
# -v es-plugins:/usr/share/elasticsearch/plugins: ES插件挂载点
# --network es-net: 容器加载到网络
# -p 9200:9200: 暴露的HTTP访问接口 
# -p 9300:9300: 暴露容器访问端口

docker run --name es \
	-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
	-e "discovery.type=single-node" \
	-v es-data:/usr/share/elasticsearch/data \
	-v es-plugins:/usr/share/elasticsearch/plugins \
	--privileged \
	--network es-net \
	-p 9200:9200 \
	-p 9300:9300 \
	-d elasticsearch:7.12.1

ここに画像の説明を挿入
アクセスポート9200

ここに画像の説明を挿入

2、部署 kibana

docker pull kibana:7.12.1

ここに画像の説明を挿入

# --network=es-net: 加入到ES的网络中
# -e ELASTICSEARCH_HOSTS=http://es:9200: 配置ES主机地址,因为在同一个网络中,所以可以直接用容器名访问ES
# -p 5601:5601: 端口映射配置
docker run --name kibana \
	-e ELASTICSEARCH_HOSTS=http://es:9200 \
	--network=es-net \
	-p 5601:5601 \
	-d kibana:7.12.1

ここに画像の説明を挿入
Kibana コンソールにアクセスする

ここに画像の説明を挿入

DSLリクエストデスク

ここに画像の説明を挿入

(8)トークナイザー

ES は、転置インデックスを作成するときに文書をセグメント化する必要があり、検索するときにユーザーが入力したコンテンツをセグメント化する必要がありますが、デフォルトの単語セグメント化ルールは中国語の処理には適していません。

Kibana コンソールを使用して中国語テストを実行します。
ここに画像の説明を挿入

中国語ワード ブレーカー IK

公式ウェブサイト: https://github.com/medcl/elasticsearch-analysis-ik

1. IK トークナイザーをデプロイする

オンライン インストールでは接続が拒否される場合があります

#进入ES容器
docker exec -it es /bin/bash

#下载 IK分词器
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip

#退出
exit

#重启容器
docker restart elasticsearch

ikをオフラインでインストールする

1. ik.7.12.1, zip
をダウンロードします。 2. 解凍後、elasticsearch-plugins データ ボリュームに転送します
。 3. docker を再起動します。

docker restart es

4. IK トークナイザーが正常にロードされていることを確認します。

docker logs -f es

ここに画像の説明を挿入
5. テスト

  • ik_smart:粗粒度の区別。分析のために 1 回だけ分割します。
    ここに画像の説明を挿入

  • ik_max_word:最もきめの細かい分割、より多くの単語を可能な限り最大に分割する

ここに画像の説明を挿入


(9) IKトークナイザーの拡張エントリと無効化エントリ

IK トークナイザーの最下層は辞書に基づいて照合され、辞書が一致する場合は直接分割され、一致しない場合は分割されません。

したがって、 IK ワード セグメンテーションを拡張する必要があります。

1. IK トークナイザーの/config/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">ext.dic</entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords">stopword.dic</entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

2. ext.dic と stopword.dic を作成します。

これら 2 つのファイルは、1 行に 1 単語ずつ改行で区切られた単なるテキスト ファイルです。

これら 2 つのファイルは config ディレクトリに設定する必要があります。設定しないと読み取ることができません。また、プラグイン作成者の辞書も config ディレクトリにあります。

3.ドッカーを再起動します

docker restart es

2. 操作インデックスライブラリ

(1) マッピング マッピング

共通のマッピング属性

  • type:フィールドのデータ型、一般的な型は次のとおりです。
    • 文字列テキスト(分割できるテキスト)、キーワード(分割できないテキスト)
    • 値: byte、short、integer、long、float、double
    • ブール値:ブール値
    • 日付:日付
    • オブジェクト:オブジェクト
    • geo_point:経度と緯度で識別されるポイント、例: "32.8138,120.58558"
    • geo_shape:直線などの複数の点で構成される幾何学的図形 LINESTRING(-77.06581831,-77.008463181)
  • Index:インデックスを作成するかどうか、デフォルトは true
  • アナライザー:使用されるトークナイザー
  • プロパティ:このフィールドのサブフィールド (オブジェクト内のプロパティなど)
  • テキスト:分詞テキスト

配列コレクションの問題について: マッピングは単一の型の複数の型をサポートします。

(2) インデックスライブラリの作成

ES は、RESTful リクエストを通じてインデックス ライブラリとドキュメントを操作します。リクエストの内容は DSL ステートメントで表されます。

インデックス ライブラリとマッピングを作成するための DSL 構文は次のとおりです。

PUT /test
{
	"mappings": {
		"properties": {
				"info": {
					"type": "text"
					"analyzer": "ik_smart
				},
				"email": {
					"type": "keyword",
					"index": "false"
				},
				"name": {
     			   "type": "object",
					"properties": {
						"firstName": {
							"type": "keyword"
						},
						"lastName": {
							"type": "keyword"
						}
					}
				}
		}
	}
}

一般的な成功効果

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

ここにはちょっとしたトリックもあります。copy_to複数フィールドの検索が必要な場合は、属性のコピーを使用できます。

"all": {
	"type": "text",
	"analyzer: "ik_max_word"
},
"brand": {
	"type": "keyword",
	"copy_to": "all"
}

(3) インデックスライブラリの参照、削除、変更

1. インデックスライブラリを表示する

GET /test

効果

{
  "test" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "email" : {
          "type" : "keyword",
          "index" : false
        },
        "info" : {
          "type" : "text",
          "analyzer" : "ik_smart"
        },
        "name" : {
          "properties" : {
            "firstName" : {
              "type" : "keyword"
            },
            "lastName" : {
              "type" : "keyword"
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "test",
        "creation_date" : "1690214456747",
        "number_of_replicas" : "1",
        "uuid" : "IIdXK-pATYOns4c8BDoaMw",
        "version" : {
          "created" : "7120199"
        }
      }
    }
  }
}

2. インデックスライブラリを削除する

DELETE /test

効果

删除成功效果
{
  "acknowledged" : true
}

再次查询索引库
{
  "error" : {
    "root_cause" : [
      {
        "type" : "index_not_found_exception",
        "reason" : "no such index [test]",
        "resource.type" : "index_or_alias",
        "resource.id" : "test",
        "index_uuid" : "_na_",
        "index" : "test"
      }
    ],
    "type" : "index_not_found_exception",
    "reason" : "no such index [test]",
    "resource.type" : "index_or_alias",
    "resource.id" : "test",
    "index_uuid" : "_na_",
    "index" : "test"
  },
  "status" : 404
}

3. インデックス ライブラリを変更します (フィールドのみ追加可能)

PUT /test/_mapping
{
	"properties": {
		"age": {
			"type": "integer
		}
	}
}

効果

新增成功
{
  "acknowledged" : true
}
再次查询/test索引库
{
  "test" : {
    "aliases" : { },
    "mappings" : {
      "properties" : {
        "age" : {
          "type" : "integer"
        },
        "email" : {
          "type" : "keyword",
          "index" : false
        },
        "info" : {
          "type" : "text",
          "analyzer" : "ik_smart"
        },
        "name" : {
          "properties" : {
            "firstName" : {
              "type" : "keyword"
            },
            "lastName" : {
              "type" : "keyword"
            }
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "test",
        "creation_date" : "1690214957185",
        "number_of_replicas" : "1",
        "uuid" : "HeoHP6GYS-uovI1DQyxEsg",
        "version" : {
          "created" : "7120199"
        }
      }
    }
  }
}

3. 文書の操作

(1) 新規文書

POST /test/_doc/1
{
	"info": "Java是最好的语言",
	"age": 18,
	"email": :"[email protected]",
	"name": {
		"firstName": "Zengoo",
		"lastName": "En"
	}
}

効果

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

(2) 文書を削除する

DELETE /test/_doc/1

効果

删除成功
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "deleted",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

再次查询
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "found" : false
}

(3) 文書の修正

PUT /test/_doc/1
{
	"info": "这是我的ES拆分Demo"
}

効果

修改成功
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}

再次查询
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "_seq_no" : 3,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "info" : "这是我的ES拆分Demo"
  }
}

PUT を直接使用して変更すると、元のドキュメントが直接上書きされることがわかります。

そこで、2 番目の変更方法を使用します。

POST /test/_update/1
{
	"doc": {
		"info": "这是我的ES拆分Demo"
	}
}

効果

更新成功
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 11,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 12,
  "_primary_term" : 1
}

查询文档
{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 11,
  "_seq_no" : 12,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "info" : "这是我的ES拆分Demo",
    "age" : 18,
    "email" : "[email protected]",
    "name" : {
      "firstName" : "Zengoo",
      "lastName" : "En"
    }
  }
}

(4) クエリ文書

GET /test/_doc/1

効果

{
  "_index" : "test",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "info" : "Java是最好的语言",
    "age" : 18,
    "email" : "[email protected]",
    "name" : {
      "firstName" : "Zengoo",
      "lastName" : "En"
    }
  }
}

4. RestClientはインデックスライブラリを操作します

(1) レストクライアント

ES は、さまざまな言語で ES クライアントを公式に提供しています。これらのクライアントの本質は、DSL ステートメントを組み立て、HTTP リクエストを通じて ES に送信することです。
公式ドキュメント: https://www.elastic.co/guide/en/elasticsearch/client/index.html

(2) RestClientのインストール

RestHighLevelClient 依存関係をインストールする

<dependency>
	<groupId>org.elasticsearch.client</groupId>
	<artifactId>elasticsearch-rest-hight-level-client</artifatId>
</dependency>

デフォルトの ES バージョンを上書きする

<properties>
	<elasticsearch.version>7.12.1</elasticsearch.version>
</properties>

RestHighLevelClient を初期化する

RestHightLevelClient client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.92.131:9200")));

(3) RestClientはインデックスライブラリを操作します

インデックスライブラリを作成する

//1、创建Request对象
CreateIndexRequest request = new CreateIndexRequest("test");
//2、请求参数,
//MAPPING_TEMPLATE 是静态常量字符串,描述的是自定义的创建索引库的DSL语句
//XContentType.JSON 是指定DSL语句以JSON格式化
request.source(MAPPING_TEMPLATE, XContentType.JSON);
//3、发起请求
//indices, 返回对象中包含的所有索引库操作方法
//RequestOptions.DEFAULT, 默认请求头
client.indices().create(request, RequestOptions.DEFAULT);

インデックスライブラリを削除する

CreateIndexRequest request = new CreateIndexRequest("test");
client.indices().delete(request, RequestOptions.DEFAULT);

インデックスライブラリの存在ステータスを問い合わせる

CreateIndexRequest request = new CreateIndexRequest("test");
boolean status = client.indices().exists(request, RequestOptions.DEFAULT);

(4) RestClient動作データ文書

文書を作成する

//根据ID查询数据, hotelService的自定义的方法getById
Hotel hotel = hotelService.getById(1L);
//转换类型,由于数据库类型与DSL类型有差异,所以需要定义一个转换类进行属性转换,即转换类构造器改造实体类。
HotelDoc hotelDoc = new HotelDoc(hotel);
//1、创建Request对象
IndexRequest request = new IndexRequest("test").id(hotel.getId().toString());
//2、准备JSON文档, 通过fastjson快速转换成json格式文本
request.source(JSON.toJSONString(hotelDoc, XContentType.JSON);
//3、发送请求
//index, 就是发送请求的那个索引
client.index(request, RequestOptions.DEFAULT);

クエリドキュメント

//1、创建request对象
GetRequest request = new GetRequest("test").id("1");
//2、发送请求,得到结果
GetResponse response = client.get(request, RequestOptions.DEFAULT);
//3、解析结果
String json = response.getSourceAsString();
System.out.println(JSON.parseObject(json, HotelDoc.class));

文書を削除する

//1、创建request对象
DeleteRequest request = new DeleteRequest("test").id("1");
//2、发送请求,得到结果
client.delete(request, RequestOptions.DEFAULT);

文書を変更する

方法 1: 完全な変更

方法2:部分変更

//1、创建Request对象
UpdateRequest request = new UpdateRequest("test","1");
//2、准备参数,每两个参数为一对
request.doc(
	"age": 18,
	"name": "Rose"
);
//3、更新文档
client.update(request, RequestOptions.DEFAULT);

ドキュメントのバッチインポート

アイデアを活用する

1. mybatis を通じてデータベース データをクエリする
2. エンティティ クラス データをドキュメント タイプ データに変換する
3. RestClient は一括バッチ処理を使用する

//1、创建Bulk请求
BulkRequest request = new BulkRequest();

//2、添加批量处理请求
for(Hotel hotel: hotels){
    
    
	HotelDoc hotelDoc = new HotelDoc(hotel);
	request.add(new IndexRequest("hotel").id(hotel.getId().toString()).source(JSON.tJSONString(hotelDoc),XContentType.JSON));
}

//3、发起请求
client.bulk(request, RequestOptions.DEFAULT);

おすすめ

転載: blog.csdn.net/Zain_horse/article/details/131902691