SpringCloudのソースコード解析(7) - Elasticsearchの統合

1。概要

ElasticSearch は、分散マルチユーザー機能を備えた全文検索エンジンを提供する Lucene ベースの検索サーバーです。 JAVA 言語に基づいて開発され、クエリと結果を返すための RESTful Web インターフェイスに基づいており、非常に人気のあるエンタープライズ レベルの検索エンジンです。 Elasticsearch の中核機能には、データの保存とデータの迅速な検索と分析が含まれます。この記事では、誰でもすぐに理解できるように、elasticsearch の基本的なプロパティとその使用法を分析します (注: この記事で説明するケースは単一ノードに基づいています)。

2.Elasticsearchの使用法

Elasticsearch のインストールについては、記事を参照してください。SpringCloud のリンク追跡 2 (Sleuth+Zipkin+Kafka+Logstash) の開始から放棄まで< a i=2>、正しいインストールと開始、アクセス アドレス: http://サーバー IP:9200/、次のデータを取得できます (インストール中の構成とバージョンが一貫していないため、一部のデータは異なる場合があります): < a i=3> インストール 成功後、Elasticsearch にはデフォルトで中国語単語分割機能がないため、中国語単語分割ツールをインストールする必要があります。
ここに画像の説明を挿入します

2.1 中国語単語セグメンタをインストールする

Elasticsearch は中国語の処理があまり得意ではないため、処理を支援するために中国語の単語セグメンターをインストールする必要があります。この記事では、次のように centos 7.6 に基づいた Elasticsearch 7.6.2 ik 単語セグメンターをインストールします。2. ボキャブラリーを構成する 上記の中国語単語分割パッケージを Elasticsearch インストール パスの plugins ディレクトリに抽出し、再起動します。Elasticsearch は単語分割パッケージを自動的に読み込みます。ダウンロードの際はzipパッケージをダウンロードしてサーバー上で解凍する必要があり、ソースコードをダウンロードするだけでは設定が不足します。 zip パッケージは次のように解凍されます。注意事項 はい、トークナイザーのバージョンは Elasticsearch のバージョンと一致している必要があります。たとえば、Elasticsearch のバージョンが 7.6.2 の場合、単語セグメンターは対応する 7.6.2 バージョンもダウンロードする必要があります。 インストール パッケージ 中国語単語セグメンター
1. Elasticsearch 中国語単語セグメンター インストール パッケージをダウンロードします

ここに画像の説明を挿入します

ここに画像の説明を挿入します

ik ワード セグメンターでは、独自の辞書を拡張して特定のシナリオに適応したり、特定の機密エントリを無効にしたりできます。変更する必要があるのは、ik ワード セグメンターの config ディレクトリにある IKAnalyzer.cfg.xml ファイルだけです。 :
ここに画像の説明を挿入します
ext.dic と stopword.dic は IKAnalyzer.cfg.xml と同じパスにあります。展開する必要がある単語を ext.dic に追加します (例: Oligui、lie equal)。 stopword.dic いくつかの禁止用語を追加します (例: ポルノ映画など)。

2.2 Elasticsearch の中核となる概念の紹介

エラスティックサーチ リレーショナルデータベース
索引 データベース
タイプ データベーステーブル
書類 データの行 (行)
分野 データの列 (列)
マッピング データベースの構成と構造 (スキーマ)

上記の概念は次のように説明されます。

1. インデックス (インデックス): インデックスは、リレーショナル データベースのデータベースに似た、類似した特性を持つドキュメントのコレクションです。通常、インデックス名はデータベース内で一意です。同じ環境。プロパティ。通常、インデックス名に基づいてドキュメントのクエリ、追加、削除、変更などを行います。
2. タイプ (type): タイプ通常、インデックスの論理的な分類またはパーティション (リレーショナル データベースのテーブルに似ています) であり、ユーザー タイプ、ロール タイプ、メニュー タイプなど、さまざまなタイプのドキュメントを 1 つのインデックスの下に保存できます。 6.0.0、タイプのみ存在できます。7.0.0 以降は非推奨となり、8.0.0 以降はまったくサポートされなくなります。現在、タイプは非推奨になりました。7.0 以降、インデックスは _doc の 1 つのタイプのみを構築できます。この段階では、インデックスはテーブルに似ています。
3. ドキュメント (ドキュメント) : ドキュメントは、インデックスを作成できる情報の基本単位です (同様に、リレーショナル データベースのデータ行に変換されます)。ドキュメントには JSON 形式のデータを保存でき、データはネストできます。複数のドキュメントを 1 つのドキュメントに保存でき、ドキュメントにはインデックスを付ける必要があります。
4. フィールド (フィールド):
ユーザー タイプの名前や年齢など、ドキュメント情報を構成する最小単位 (リレーショナル データベースの列に似ています)。
5マッピング: ドキュメントとドキュメントに含まれるフィールドの保存方法とインデックス付けの方法を定義するために使用されます (リレーショナル データベースのスキーマと同様)。マッピングの共通属性には、タイプ (データ型)、インデックス (インデックスを付けるかどうか)、アナライザー (単語セグメンター)、およびプロパティ (サブフィールド) が含まれます。

中核的な概念には、次のようなクラスター、ノード、シャードも含まれます。

名前 コンセプト
集まる ElasticSearch クラスターは実際には分散システムです。他の分散システムと同様に、データとサービスの高可用性を確保するためのものです。クラスターには複数のノードがあります。リクエスト量とデータ量が増大し続けるにつれて、システムは均等に分散できます。異なるノードを使用して水平方向の拡張を実現します。
ノード 各ノードは JAVA プロセスである ElasticSearch サービスです。クラスターを形成する最小単位です。各ノードには一意の名前があります。デフォルトでは、ノードの起動時にノード名として uuid が生成されます (名前は、クラスタは任意の数のノードで構成できます。ノードが 1 つだけ起動されている場合、それは単一ノード クラスタです。
断片化 シャーディングはノード容量制限の問題を解決するために使用されます。リレーショナル データベースの水平シャーディングと同様に、プライマリ シャーディングを通じてクラスター内のすべてのノードにデータを分散できます。シャードは Lucene インスタンスであり、データにはインデックスが付けられます。シャーディングでは、プログラムは (シャーディングではなく) インデックスを直接操作します。

2.2 SpringBoot は Elasticsearch を統合します

springboot と elasticsearch の間で対応するバージョン情報を次の図に示します。
ここに画像の説明を挿入します
この記事で使用されている Elasticsearch のバージョンは 7.6.2 であるため、対応する SpringBoot のバージョンはバージョン 2.3 です。 7。

2.2.1 pomの導入

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

2.2.2 ElasticSearchの操作

この記事では、RestHighLevelClient を使用して ElasticSearch の操作をデモンストレーションします。RestHighLevelClient オブジェクトの具体的な作成と破棄は次のとおりです (デモンストレーション目的のため、運用環境での使用は推奨されません)。

    //创建RestHighLevelClient对象
    @Before
    public void setUp() {
    
    
        this.restHighLevelClient = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://127.0.0.1:9200")
        ));
        log.info("创建RestHighLevelClient");
    }

    //销毁RestHighLevelClient对象
    @After
    public void clear() {
    
    
        try {
    
    
            this.restHighLevelClient.close();
            log.info("销毁RestHighLevelClient");
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }

1. インデックスの作成
ES では、Restful API インターフェイスを介してインデックス ライブラリとドキュメントの操作が要求され、要求の内容は DSL で表されます。インデックス ライブラリとマッピングを作成するための構文は次のとおりです (book という名前のインデックスを作成します)。

PUT /book
{
    
    
    "mappings" : {
    
    
        "properties" : {
    
    
          "brand" : {
    
    
            "type" : "keyword"
          },
          "category" : {
    
    
            "type" : "keyword"
          },
          "id" : {
    
    
            "type" : "keyword"
          },
          "images" : {
    
    
            "type" : "keyword",
            "index" : false
          },
          "price" : {
    
    
            "type" : "double"
          },
          "title" : {
    
    
            "type" : "text",
            "analyzer" : "ik_max_word"
          },
          "address" : {
    
    
            "type" : "text",
            "analyzer" : "ik_max_word"
          },
          "publisher" : {
    
    
            "type" : "keyword"
          }
      }
    }
}

マッピングは、インデックス データベース内のドキュメントに対する制約です。一般的なマッピング属性には次のものがあります。

(1) type: フィールド データ型 一般的な単純型には、文字列型、数値型、およびブール型が含まれます。
文字列: テキスト (単語で区切られたテキスト)、キーワード (国、都市、IP アドレスなどの正確な値);
値には次のものが含まれますbyte、short、integer、long、double、float、ブール型はブール型のみ、日付型は日付、オブジェクト型はオブジェクト (内部に属性を含むことができる) であり、基本的に JAVA 構文の型と同じです。 ;
この部分は、「JAVA の変数の型は一貫している」と同じです。
(2) インデックス: インデックスを作成するかどうか、デフォルトは true;
(3) アナライザ: どの単語セグメンタを使用するか、デフォルトは英単語セグメンテーション、中国語の単語のセグメンテーション ツールには、ik_max_word (共通モード、テキストを最も細かい粒度に分割)、ik_smart (テキストを最も粗い粒度に分割)、
(4) プロパティ: のサブフィールドが含まれます。このフィールド;

SpringBoot を使用してインデックスを作成することに対応するコードは次のとおりです。

   @Test
    public void testCreateBookIndex() throws Exception {
    
    
        CreateIndexRequest request = new CreateIndexRequest("book");
        request.source(Constants.BOOK_STRING, XContentType.JSON);
        restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
        System.out.println(restHighLevelClient);
    }
	
//对应常量Constants中BOOK_STRING 
public class Constants {
    
    

    public static final String BOOK_STRING = "{\n" +
            "    \"mappings\": {\n" +
            "            \"properties\": {\n" +
            "                \"id\": {\n" +
            "                    \"type\": \"keyword\"\n" +
            "                },\n" +
            "                \"title\": {\n" +
            "                    \"type\": \"text\",\n" +
            "                    \"analyzer\": \"ik_max_word\"\n" +
            "                },\n" +
            "                \"category\": {\n" +
            "                    \"type\": \"keyword\"\n" +
            "                },\n" +
            "                \"brand\": {\n" +
            "                    \"type\": \"keyword\"\n" +
            "                },\n" +
            "                \"images\": {\n" +
            "                    \"type\": \"keyword\",\n" +
            "                    \"index\":  false\n" +
            "                },\n" +
            "                \"price\": {\n" +
            "                    \"type\": \"double\"\n" +
            "                }\n" +
            "            }\n" +
            "    }\n" +
            "}";
}

コード作成が成功すると、次の結果が返されます:
ここに画像の説明を挿入します
2. インデックスが存在するかどうかを確認する
RESTful インターフェイスをリクエストする操作は次のとおりです。次のとおりです:

GET /インデックス名

クエリ インデックスは book です。存在する場合、返される結果は次のとおりです。

{
    
    
  "book" : {
    
    
    "aliases" : {
    
     },
    "mappings" : {
    
    
      "properties" : {
    
    
        "brand" : {
    
    
          "type" : "keyword"
        },
        "category" : {
    
    
          "type" : "keyword"
        },
        "id" : {
    
    
          "type" : "keyword"
        },
        "images" : {
    
    
          "type" : "keyword",
          "index" : false
        },
        "price" : {
    
    
          "type" : "double"
        },
        "title" : {
    
    
          "type" : "text",
          "analyzer" : "ik_max_word"
        }
      }
    },
    "settings" : {
    
    
      "index" : {
    
    
        "creation_date" : "1688459211404",
        "number_of_shards" : "1",
        "number_of_replicas" : "1",
        "uuid" : "inX1UEwZSGyB3fovFAzt2g",
        "version" : {
    
    
          "created" : "7060299"
        },
        "provided_name" : "book"
      }
    }
  }
}

Springboot での判定には次のコードを使用できます。

   @Test
    public void testExistBookIndex() throws Exception {
    
    
        GetIndexRequest request = new GetIndexRequest("book");
        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        log.info("exists :{}", (exists ? "索引库已经存在" : "索引库不存在"));
    }

インデックスが存在する場合、実行結果は次のようになります:
ここに画像の説明を挿入します
3. インデックスを削除します
インデックス ライブラリを削除するための構文は次のとおりです。 :

DELETE /インデックス名

Springboot のコードを使用して、次のように削除します。

  @Test
    public void testDeleteBookIndex() throws Exception {
    
    
        DeleteIndexRequest request = new DeleteIndexRequest("book");
        restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
        log.info("索引删除成功");
    }

実行結果は次のとおりです。
ここに画像の説明を挿入します
4. インデックス ライブラリを更新する
インデックス ライブラリとマッピングは作成後は変更できませんが、新しいものは作成されます。フィールドを追加できます。構文は次のとおりです。

PUT /book/_mapping
{
    
    
   "properties": {
    
    
     "name": {
    
    
       "type": "keyword",
       "index": false       
     }
 }
}

esの操作クラスRestHighLevelClientには、インデックスを直接変更する操作メソッドが提供されていません。

5. ドキュメントを追加する
ドキュメントを追加するための構文は次のとおりです:

POST /索引名称/_doc/文档id
{
    
    
  "address" : "杭州市西湖区",
  "brand" : "莫言文学",
  "category" : "世界文学",
  "id" : 2,
  "images" : "http://1288779/1.image",
  "price" : 109.0,
  "publisher" : "浙江鲁迅文学出版社",
  "title" : "《丰乳肥臀》"
}

追加が成功した後に返される結果は次のとおりです。
ここに画像の説明を挿入します
Springboot を使用してドキュメントを追加する操作は次のとおりです。

   @Test
    public void testAddBookDocument() throws Exception {
    
    
        IndexRequest request = new IndexRequest("book").id("2");
        Book book1 = new Book();
        book1.setBrand("莫言文学出版社");
        book1.setCategory("世界文学");
        book1.setId(2L);
        book1.setImages("http://1288779/1.image");
        book1.setPrice(109.0);
        book1.setTitle("《丰乳肥臀》");
        book1.setPublisher("浙江鲁迅文学出版社");
        book1.setAddress("杭州市西湖区");
        request.source(JSON.toJSONString(book1), XContentType.JSON);
        restHighLevelClient.index(request, RequestOptions.DEFAULT);
        log.info("添加书籍书籍成功:{}", JSON.toJSONString(book1));
    }

6. ID に基づいてドキュメントをクエリする
ID に基づいてドキュメントをクエリするための構文は次のとおりです。

GET /index_name/_doc/id

Springboot が ID に基づいてドキュメントをクエリする方法は次のとおりです。

   @Test
    public void testSearchBookDocument() throws Exception {
    
    
        GetRequest request = new GetRequest("book", "1");
        GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
        String result = response.getSourceAsString();
        log.info("查询返回结果为:{}", result);
        if (StringUtils.isNotBlank(result)) {
    
    
            Book book = JSON.parseObject(result, Book.class);
            log.info("book:{}", book.toString());
        }
    }

クエリ結果は次のとおりです:
ここに画像の説明を挿入します
7. ドキュメントを変更する
ドキュメントを変更するには主に 2 つの方法があります。全額変更 (古いドキュメントを削除し、新しいドキュメントを追加)、もう 1 つは増分変更 (指定されたフィールド値を変更) です。完全な変更の構文は次のとおりです。

PUT /索引库名/_doc/文档id
{
    
    
  "doc"{
    
    
  "字段1" : "值1",
  "字段2" : "值2",
  //......
  }
}

増分変更の構文は次のとおりです。

POST /索引库名/_update/文档id
{
    
    
  "doc"{
    
    
  "字段1" : "值1",
  "字段2" : "值2",
  //......
  }
}

スプリングブートの増分変更コードは次のとおりです。

  @Test
    public void testUpdateBookDocument() throws Exception {
    
    
        UpdateRequest request = new UpdateRequest("book", "1");
        request.doc((jsonBuilder()
                .startObject()
                .field("brand", "山东文学出版社")
                .endObject()));
        restHighLevelClient.update(request, RequestOptions.DEFAULT);
        log.info("更新数据成功!");
    }

更新後、クエリは次の結果を返します:
ここに画像の説明を挿入します
8. ID に基づいてドキュメントを削除する
ドキュメントを削除するための構文は次のとおりです。

DELETE /インデックス名/_doc/id

ID に基づいた Springboot 削除ドキュメント コードは次のとおりです。

@Test
public void testDeleteBookDocument() throws Exception {
    
    
    DeleteRequest request = new DeleteRequest("book", "1");
    restHighLevelClient.delete(request, RequestOptions.DEFAULT);
    log.info("删除数据成功!");
    //testSearchProductDocument();
}

9. ドキュメントをバッチで追加する

 @Test
    public void testBulkBookDocument() throws Exception {
    
    
        BulkRequest bulkRequest = new BulkRequest();
        IndexRequest request = new IndexRequest("book").id("2");
        Book book1 = new Book();
        book1.setBrand("莫言文学出版社");
        book1.setCategory("中国文学");
        book1.setId(1L);
        book1.setImages("pic1,pic2");
        book1.setPrice(99.0);
        book1.setTitle("《蛙》");
        request.source(JSON.toJSONString(book1), XContentType.JSON);
        log.info("添加数据成功!");

        IndexRequest request1 = generateBook();
        log.info("添加数据成功!");


        bulkRequest.add(request);
        bulkRequest.add(request1);
		//批量添加
        restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        //testSearchProductDocument();
    }

    //CURL+ALT+M 抽取方法
    private IndexRequest generateBook() {
    
    
        IndexRequest request1 = new IndexRequest("book").id("3");
        Book book2 = new Book();
        book2.setBrand("莫言文学出版社");
        book2.setCategory("中国文学");
        book2.setId(1L);
        book2.setImages("pic1,pic2");
        book2.setPrice(99.0);
        book2.setTitle("《酒国》");
        request1.source(JSON.toJSONString(book2), XContentType.JSON);
        return request1;
    }

バッチ追加では、restHighLevelClient のBulk メソッドを使用し、アセンブルされた IndexRequest オブジェクトを BulkRequest オブジェクトに追加し、最後にBulk メソッドを呼び出してそれらをデータベースに均一に保存します。

2.3 DSL クエリ構文

Elasticsearch は、クエリを定義するための JSON ベースの DSL (Domain Specific Language) を提供します。一般的なクエリの種類は次のとおりです。

(1) すべてクエリ: すべてのデータをクエリします。通常はテストに使用されます。例: match_all;
(2) 全文検索クエリ (フル テキスト): 単語セグメンタを使用します。ユーザー入力を入力します。コンテンツは単語に分割され、転置インデックス ライブラリで照合されます。例: match_query, multi_match_query;
(3) 正確なクエリ: 正確なエントリ値 (通常はキーワード、数値、日付、ブール値、およびその他のタイプのフィールド) に基づいてデータを検索します。例: id、range、term;
(4) 地理クエリ (geo): 経度と緯度に基づくクエリ。例: geo_ distance, geo_bounding_box;
(5) 複合クエリ (compound): 複合条件は、上記のさまざまなクエリ条件を組み合わせて、クエリ条件をマージします。例: bool、function_score;

2.3.1 match_all

match_all クエリ構文は次のとおりです。

GET /index/_search 
{
    
    
  "query": {
    
    
    "match_all": {
    
    }
  }
}

スプリングブートのコードは次のとおりです。

   @Test
    public void testMatchAll() throws Exception {
    
    
        SearchRequest searchRequest = new SearchRequest("book");
        searchRequest.source().query(QueryBuilders.matchAllQuery());
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        log.info("result:{}", response);
        SearchHits hits = response.getHits();
        TotalHits totalHits = hits.getTotalHits();
        log.info("总数为total:{}", totalHits);
        SearchHit[] hitsList = hits.getHits();
        for (SearchHit documentFields : hitsList) {
    
    
            String sourceAsString = documentFields.getSourceAsString();
            log.info("查询结果:{}", sourceAsString);
        }
    }

実行結果は次のとおりです。
ここに画像の説明を挿入します

2.3.2 全文検索クエリ

全文検索クエリはユーザー入力コンテンツを単語に分割し、検索ボックスの検索でよく使用されます。全文検索には主に match、multi_match が含まれます。 match は、ユーザー入力コンテンツを単語に分割し、転置インデックス データベース内で検索します。構文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
    "match": {
    
    
      "FIELD": "TEXT"
    }
  }
}

multi_match は match クエリに似ていますが、同僚が複数のフィールドをクエリできる点が異なります。構文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
   "multi_match": {
    
    
     "query": "TEXT",
     "fields": ["FIELD1","FIELD2"]
   }
  }
}

match は 1 つのフィールドに基づいてクエリを実行する場合に使用され、multi_match は複数のフィールドに基づいてクエリを実行する場合に使用されます (クエリ フィールドが増えるとパフォーマンスが低下します)。使用する場合は、可能な限り Match を使用する必要があります。
springboot の一致クエリ コードは次のとおりです。

 @Test
    public void testMatchQuery() throws Exception {
    
    
        SearchRequest searchRequest = new SearchRequest("book");
        searchRequest.source().query(QueryBuilders.matchQuery("all", "莫言"));
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        log.info("result:{}", response);
        SearchHits hits = response.getHits();
        TotalHits totalHits = hits.getTotalHits();
        log.info("总数为total:{}", totalHits);
        SearchHit[] hitsList = hits.getHits();
        for (SearchHit documentFields : hitsList) {
    
    
            String sourceAsString = documentFields.getSourceAsString();
            log.info("查询结果:{}", sourceAsString);
        }
    }

2.3.3 正確なクエリ

正確なクエリでは通常、キーワード、値、日付、ブール値、その他の種類のフィールドが検索されるため、検索条件はセグメント化されません。一般的な正確なクエリには、用語と範囲が含まれます。用語は用語の正確な値に基づいてクエリされ、範囲は値の範囲に基づいてクエリされます。

//查询价格为109的书籍
GET /book/_search
{
    
    
  "query": {
    
    
    "term": {
    
    
      "price": {
    
    
        "value": 109
      }
    }
  }
}

Springboot は次のように用語クエリ コードを使用します。

 @Test
    public void testBooleanQuery() throws Exception {
    
    
        SearchRequest searchRequest = new SearchRequest("book");
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("price", 109));
        //range是范围查询
        //boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gt(100));
        searchRequest.source().query(boolQueryBuilder);

        //分页
        searchRequest.source().from(0).size(10);

        //排序
        //searchRequest.source().sort("price", SortOrder.ASC);

        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        log.info("result:{}", response);
        SearchHits hits = response.getHits();
        TotalHits totalHits = hits.getTotalHits();
        log.info("总数为total:{}", totalHits);
        SearchHit[] hitsList = hits.getHits();
        for (SearchHit documentFields : hitsList) {
    
    
            String sourceAsString = documentFields.getSourceAsString();
            log.info("查询结果:{}", sourceAsString);
        }
    }

結果は次のとおりです。
ここに画像の説明を挿入します
範囲クエリの構文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
    "range": {
    
    
      "price": {
    
    
        "gte": 100,
        "lte": 200
      }
    }
  }
}

2.3.4 地理的クエリ

地理的なクエリは主に経度と緯度に基づいており、使用シナリオには、WeChat の近くにいる人、近くのホテル、近くの企業などが含まれます。クエリ構文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
  "geo_distance": {
    
    
    "distance": "10km",
    "FIELD": "31.21,121.5"
  }
  }
}

2.3.5 複合クエリ

1. スコア機能
複合クエリは複数の条件を組み合わせて、より複雑な検索を実現します。例: 関数スコア (スコア関数)。
スコアリング関数を使用して、ドキュメントの関連性を制御し、ドキュメントのランキングを制御できます。クエリ構文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
    "function_score": {
    
    
      "query": {
    
    
        "match": {
    
    
          "brand": "莫言文学"
        }
      },//原始查询条件,搜索相关文档并进行打分
      "functions": [
        {
    
    "filter": {
    
    
          "term": {
    
    
            "id": "1"
          }
        },//过滤条件,复合条件的文档才会被重新打分
          "weight": 10  //算分函数,算分函数会得到计算结果function score,将来会与query score运算,得到新算分
        }
      ],
       "boost_mode": "multiply"  //加权模式,定义function score与query score的运算方式,multiply是两者相乘,还有sum、avg、max等
    }
  }
}

結果は次のとおりです。

{
    
    
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    
    
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    
    
    "total" : {
    
    
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : 3.791412,
    "hits" : [
      {
    
    
        "_index" : "book",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 3.791412,
        "_source" : {
    
    
          "brand" : "莫言文学出版社",
          "category" : "中国文学",
          "id" : 1,
          "images" : "pic1,pic2",
          "price" : 99.0,
          "score" : 0.0,
          "title" : "《蛙》"
        }
      },
      {
    
    
        "_index" : "book",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 3.791412,
        "_source" : {
    
    
          "brand" : "莫言文学出版社",
          "category" : "中国文学",
          "id" : 1,
          "images" : "pic1,pic2",
          "price" : 99.0,
          "score" : 0.0,
          "title" : "《酒国》"
        }
      },
      {
    
    
        "_index" : "book",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.47436732,
        "_source" : {
    
    
          "address" : "杭州市西湖区",
          "brand" : "莫言文学",
          "category" : "世界文学",
          "id" : 2,
          "images" : "http://1288779/1.image",
          "price" : 109.0,
          "publisher" : "浙江鲁迅文学出版社",
          "title" : "《丰乳肥臀》"
        }
      },
      {
    
    
        "_index" : "book",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.47436732,
        "_source" : {
    
    
          "address" : "上海市静安区",
          "brand" : "莫言文学",
          "category" : "中国文学",
          "id" : 3,
          "images" : "pic1,pic2",
          "price" : 109.0,
          "publisher" : "北京文学出版社",
          "title" : "《红高粱》"
        }
      }
    ]
  }
}

一般的な分数関数には次のものがあります。

(1) 重み: 指定された定数値を関数の結果 (関数スコア) として与えます。
(2) field_value_factor: ドキュメント内の特定のフィールド値を関数の結果として使用します。 ;
(3)random_score: 関数の結果として値をランダムに生成します;
(4) script_score: 計算式をカスタマイズし、計算式の結果は次のように使用されます。関数の結果。

2. ブール クエリ
ブール クエリは、1 つ以上のクエリ句の組み合わせです。サブクエリの組み合わせは次のとおりです。

(1) 必須: 「and」のように、すべてのサブクエリと一致する必要があります。
(2) すべき: 「or」のように、サブクエリを選択的に一致させます。 < a i=2> (3) must_not: 一致する必要があり、スコアリングに参加しません。「not」と同様です。 (4) filter: 一致する必要があり、スコアリングに参加しません。

クエリ文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
    "bool": {
    
    
      "must": [
        {
    
    
          "match": {
    
    
          "brand": "莫言文学"
        }}
      ],
      "should": [
        {
    
    "term": {
    
    
          "id": {
    
    
            "value": 1
          }
        }
        },
        {
    
    "term": {
    
    
          "id": {
    
    
            "value": 1
          }
        }
        }
      ], 
      "must_not": [
        {
    
    
          "range": {
    
    
          "price": {
    
    
            "lt": 100
          }
        }}
      ]
    }
  }
  
}

クエリ結果は次のとおりです。

{
    
    
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    
    
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    
    
    "total" : {
    
    
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.47436732,
    "hits" : [
      {
    
    
        "_index" : "book",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.47436732,
        "_source" : {
    
    
          "address" : "杭州市西湖区",
          "brand" : "莫言文学",
          "category" : "世界文学",
          "id" : 2,
          "images" : "http://1288779/1.image",
          "price" : 109.0,
          "publisher" : "浙江鲁迅文学出版社",
          "title" : "《丰乳肥臀》"
        }
      },
      {
    
    
        "_index" : "book",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 0.47436732,
        "_source" : {
    
    
          "address" : "上海市静安区",
          "brand" : "莫言文学",
          "category" : "中国文学",
          "id" : 3,
          "images" : "pic1,pic2",
          "price" : 109.0,
          "publisher" : "北京文学出版社",
          "title" : "《红高粱》"
        }
      }
    ]
  }
}

3. ハイライト フィールド
ハイライト フィールドは、実際には指定されたクエリ フィールドにラベルを返します。フロント エンドは、このラベルに基づいて CSS スタイルを記述して、ハイライトやその他の目的を実現できます。強調表示されている構文は次のとおりです。

GET /book/_search
{
    
    
  "query": {
    
    
    "match": {
    
    
      "brand": "莫言文学"  //查询字段
    }
  },
  //需要高亮的字段,添加前置和后置标签
  "highlight": {
    
    
    "fields": {
    
    
      "brand": {
    
    
        "pre_tags": "<em>",
        "post_tags": "</em>"
      }
    }
  }
}

スプリングブートのコードは次のとおりです。

 @Test
    public void testHighlightQuery() throws Exception {
    
    
        SearchRequest searchRequest = new SearchRequest("book");
        searchRequest.source().query(QueryBuilders.matchQuery("brand", "莫言文学"));
        //高亮
        searchRequest.source().highlighter(new HighlightBuilder().field("brand").requireFieldMatch(false));
        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        log.info("result:{}", response);
        SearchHits hits = response.getHits();
        TotalHits totalHits = hits.getTotalHits();
        log.info("总数为total:{}", totalHits);
        SearchHit[] hitsList = hits.getHits();
        for (SearchHit hit : hitsList) {
    
    
            String sourceAsString = hit.getSourceAsString();
            Book book = JSON.parseObject(sourceAsString, Book.class);
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlightField = highlightFields.get("brand");
            String string = highlightField.getFragments()[0].string();
            book.setBrand(string);
            log.info("查询结果:{}", string);
        }
    }

結果は次のとおりです。
ここに画像の説明を挿入します

3. まとめ

1.ik 単語セグメンターは、中国語のパターンをより適切に識別するのに役立ちます。
2. elasticsearch、kibana、springboot を使用する場合は、バージョンの一貫性に注意してください。
3. ES では、Restful API インターフェイスを使用してインデックス ライブラリとドキュメントの操作をリクエストし、リクエストの内容は DSL で表現されます。

4. 参考文献

1.https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html
2.https://www.bilibili.com /video/BV1LQ4y127n4
3.https://www.elastic.co/cn/downloads/past-releases/kibana-7-6-2

5. 付録

1.https://gitee.com/Marinc/nacos.git

おすすめ

転載: blog.csdn.net/qq_33479841/article/details/130369492