elasticsearch相關2

张碧晨發表於2024-04-19

1.資料聚合

1.1.聚合的種類

聚合常見的有三類:

- **桶(Bucket)**聚合:用來對文件做分組
- TermAggregation:按照文件欄位值分組,例如按照品牌值分組、按照國家分組
- Date Histogram:按照日期階梯分組,例如一週為一組,或者一月為一組

- **度量(Metric)**聚合:用以計算一些值,比如:最大值、最小值、平均值等
- Avg:求平均值
- Max:求最大值
- Min:求最小值
- Stats:同時求max、min、avg、sum等
- **管道(pipeline)**聚合:其它聚合的結果為基礎做聚合

注意:**參加聚合的欄位必須是keyword、日期、數值、布林型別

1.2.DSL實現聚合

1.2.1.Bucket聚合語法

GET /hotel/_search
{
  "size": 0,  // 設定size為0,結果中不包含文件,只包含聚合結果
  "aggs": { // 定義聚合
    "brandAgg": { //給聚合起個名字
      "terms": { // 聚合的型別,按照品牌值聚合,所以選擇term
        "field": "brand", // 參與聚合的欄位
        "size": 20 // 希望獲取的聚合結果數量
      }
    }
  }
}

1.2.2.聚合結果排序

預設情況下,Bucket聚合會統計Bucket內的文件數量,記為_count,並且按照_count降序排序。

我們可以指定order屬性,自定義聚合的排序方式:

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "order": {
          "_count": "asc" // 按照_count升序排列
        },
        "size": 20
      }
    }
  }
}

1.2.3.限定聚合範圍

預設情況下,Bucket聚合是對索引庫的所有文件做聚合,但真實場景下,使用者會輸入搜尋條件,因此聚合必須是對搜尋結果聚合。那麼聚合必須新增限定條件。

我們可以限定要聚合的文件範圍,只要新增query條件即可:

GET /hotel/_search
{
  "query": {
    "range": {
      "price": {
        "lte": 200 // 只對200元以下的文件聚合
      }
    }
  }, 
  "size": 0, 
  "aggs": {
    "brandAgg": {
      "terms": {
        "field": "brand",
        "size": 20
      }
    }
  }
}

1.2.4.Metric聚合語法

現在我們需要對桶內的酒店做運算,獲取每個品牌的使用者評分的min、max、avg等值。

這就要用到Metric聚合了,例如stat聚合:就可以獲取min、max、avg等結果。

GET /hotel/_search
{
  "size": 0, 
  "aggs": {
    "brandAgg": { 
      "terms": { 
        "field": "brand", 
        "size": 20
      },
      "aggs": { // 是brands聚合的子聚合,也就是分組後對每組分別計算
        "score_stats": { // 聚合名稱
          "stats": { // 聚合型別,這裡stats可以計算min、max、avg等
            "field": "score" // 聚合欄位,這裡是score
          }
        }
      }
    }
  }
}

這次的score_stats聚合是在brandAgg的聚合內部巢狀的子聚合。因為我們需要在每個桶分別計算。

RestAPI實現聚合

聚合條件與query條件同級別,因此需要使用request.source()來指定聚合條件。

@SpringBootTest(classes = ElasticApplication.class)
@RunWith(SpringRunner.class)
public class HotelAggregationTest {
    private RestHighLevelClient client;

    @Test
    void testSearchAggRequest() throws IOException {
        SearchRequest request = new SearchRequest("hotel");
        request.source().size(0);
        request.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(20));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        Aggregations aggregations = response.getAggregations();
        Terms brandAgg = aggregations.get("brandAgg");
        List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();
        // 4.3.遍歷
        for (Terms.Bucket bucket : buckets) {
            String brandName = bucket.getKeyAsString();
            System.out.println("brandName = " + brandName);
            long docCount = bucket.getDocCount();
            System.out.println("docCount = " + docCount);
        }
    }

    @BeforeEach
    void setUp() {
        client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://localhost:9200")
        ));
    }

    @AfterEach
    void tearDown() throws IOException {
        client.close();
    }
}

2.自動補全

2.1.拼音分詞器

要實現根據字母做補全,就必須對文件按照拼音分詞。在GitHub上恰好有elasticsearch的拼音分詞外掛。地址:https://github.com/medcl/elasticsearch-analysis-pinyin

相關文章