Bu örnekte, dizini sorgulamak ve Golang'daki sonuç kümesini sayfalandırmak için Elasticsearch'ün Search API'sini kullanacağız. Klasik from ve size parametrelerini kullanacağız çünkü from+size her zaman 10000'den küçük veya ona eşit olacaktır. Ancak, bunu garanti edemezseniz, onun yerine Search after özelliğine bağlı kalmalısınız. Bu özelliğin en iyi yanı, Point in Time API (PIT) kullanmasıdır. Sayfalandırma istekleri arasında bir yenileme gerçekleştiğinde, sonucun sırası değişebilir ve bu da sayfalar arasında tutarsızlığa neden olabilir. Point in Time API, bu tür bir sorunu önlemek için mevcut dizin durumunu korur.


Dosyalar


Bu, önceki Golang ile basit bir Elasticsearch CRUD örneği yazısının devamıdır, bu yüzden burada aynı şeyleri tekrarlamıyorum.


elasticsearch.go


package elasticsearch

...

// postsResponse represents list of posts in Search API response body.
type postsResponse struct {
Hits struct {
Total struct {
Value int `json:"value"`
} `json:"total"`
Hits []struct {
Source *storage.Post `json:"_source"`
} `json:"hits"`
} `json:"hits"`
}

post_storer.go


package storage

...

type PostStorer interface {
...
// The returned `int` represents all the found docs, not the ones in the current page!
ListAll(ctx context.Context, from, size int) (int, []*Post, error)
}

elasticsearch.go


package elasticsearch

...

// Validation
// from >= 0
// size >= 0
// from+size <= 10000
func (p PostStorage) ListAll(ctx context.Context, from, size int) (int, []*storage.Post, error) {
// res, err := p.elastic.client.Search()
req := esapi.SearchRequest{
Index: []string{p.elastic.alias},
From: &from,
Size: &size,
}

ctx, cancel := context.WithTimeout(ctx, p.timeout)
defer cancel()

res, err := req.Do(ctx, p.elastic.client)
if err != nil {
return 0, nil, fmt.Errorf("list all: request: %w", err)
}
defer res.Body.Close()

if res.IsError() {
return 0, nil, fmt.Errorf("list all: response: %s", res.String())
}

var body postsResponse
if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
return 0, nil, fmt.Errorf("list all: decode: %w", err)
}

posts := make([]*storage.Post, len(body.Hits.Hits))
for i, v := range body.Hits.Hits {
posts[i] = v.Source
}

return body.Hits.Total.Value, posts, nil
}