Intro::
gin gonic, elasticsearch를 활용한 Search API 구현 프로젝트입니다.
초기 설정
•
elasticsearch에 넣을 데이터와 인덱스는 엘라스틱서치 실무 가이드에서 제공하는 스냅샷을 사용하였습니다.
docker-compose.yml
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.8.1
container_name: es01
environment:
- cluster.name=javacafe-cluster
- node.name=es01
- network.host=0.0.0.0
- http.port=9200
- transport.tcp.port=9300
- cluster.initial_master_nodes=es01
- path.repo=/es/book_backup/search_example
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data01:/usr/share/elasticsearch/data
- ./search_example:/es/book_backup/search_example
ports:
- 9200:9200
- 9300:9300
networks:
- elastic
kibana:
image: docker.elastic.co/kibana/kibana:7.8.1
container_name: kibana
restart: always
environment:
ELASTICSEARCH_HOSTS: http://es01:9200
ports:
- 5601:5601
depends_on:
- es01
networks:
- elastic
volumes:
data01:
driver: local
networks:
elastic:
driver: bridge
YAML
복사
데이터 넣어주기
// kibana를 사용해서 elasticsearch에서 스냅샷 복구
// 스냅샷 등록
PUT _snapshot/search_example
{
"type": "fs",
"settings": {
"location": "/es/book_backup/search_example",
"compress": true
}
}
// 스냅샷 등록 확인
GET _snapshot/search_example/_all
// 스냅샷 복구
POST _snapshot/search_example/movie-search/_restore
JSON
복사
go.mod
go get -u github.com/gin-gonic/gin# gin gonic 설치
go get github.com/olivere/elastic/v7# olivere/elastic 설치
go get -u golang.org/x/sync/errgroup
Bash
복사
gin gonic
Gin Gonic은 Go 언어로 작성된 고성능 웹 프레임워크입니다. 주로 RESTful API를 구축하는 데 사용되며, 간결하고 직관적인 API를 제공하여 개발자가 빠르게 웹 애플리케이션을 개발할 수 있도록 돕습니다.
주요 특징
1.
고성능: Gin Gonic은 HTTP 요청을 빠르게 처리할 수 있도록 최적화되어 있습니다.
2.
간결한 코드: 최소한의 코드로 웹 서버와 라우트를 설정할 수 있습니다.
3.
미들웨어 지원: 인증, 로깅, CORS 등 다양한 미들웨어를 쉽게 추가할 수 있습니다.
4.
라우팅: RESTful 라우팅을 지원하며, 경로 파라미터, 쿼리 스트링 등의 다양한 요청 데이터를 쉽게 처리할 수 있습니다.
5.
JSON 처리: JSON 요청 및 응답 처리가 매우 간편합니다.
6.
컨텍스트: 요청 수명 주기 동안 상태를 유지하고 공유할 수 있도록 컨텍스트 객체를 제공합니다.
예제 코드
package main
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
)
type Album struct {
ID string `json:"id" binding:"required"`
Title string `json:"title" binding:"required"`
Artist string `json:"artist" binding:"required"`
Price float64 `json:"price" binding:"required"`
}
var albums = []Album{
{ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
{ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
{ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}
func getAlbums(c *gin.Context) {
c.IndentedJSON(http.StatusOK, albums)
}
func postAlbums(c *gin.Context) {
var newAlbum Album
if err := c.BindJSON(&newAlbum); err != nil {
log.Println(err)
c.Status(http.StatusBadRequest)
return
}
log.Println("GOOD~~")
albums = append(albums, newAlbum)
c.IndentedJSON(http.StatusCreated, newAlbum)
}
func main() {
router := gin.Default()
router.GET("/albums", getAlbums)
router.POST("/albums", postAlbums)
router.Run("localhost:8080")
}
Go
복사
olivere/elastic
package elasticconn
import (
"context"
"log"
"time"
"github.com/olivere/elastic/v7"
)
var (
EsClient *elastic.Client
)
func InitEs() {
EsClient, _ = elastic.NewClient(
elastic.SetURL("http://localhost:9200"), // elasticsearch 서버 설정 & ','으로 다수 등록 가능
elastic.SetSniff(false), // 클러스터 sniffing 비활성화
elastic.SetHealthcheckInterval(10*time.Second), // 클러스터 상태 확인 간격 설정
elastic.SetRetrier(elastic.NewBackoffRetrier(elastic.NewExponentialBackoff(100*time.Millisecond, 10*time.Second)))) // 재시도 전략
if _, err := EsClient.CatHealth().Do(context.TODO()); err != nil {
log.Println("ELASTIC CLIENT 연결 실패", err)
} else {
log.Println("ELASTIC CLIENT 연결 성공!!!")
}
}
Go
복사
Swagger 적용
go get -u github.com/swaggo/swag/cmd/swag
go get -u github.com/swaggo/gin-swagger
go get -u github.com/swaggo/files
Bash
복사
// main.go 파일 설정
import (
ginSwagger "github.com/swaggo/gin-swagger"
swaggerFiles "github.com/swaggo/files"
_ "searchAPI/cmd/docs"// docs 경로는 상황에 맞게 작성해두면 된다.
)
func main() {
e := gin.New()// 혹은 gin.Default()로 생성한 Gin 엔진
e.GET("/api/v1/ping", requestPing)
setUpSwagger(e)
}
// @title Swagger SearchAPI
// @version 1.0
// @description SearchAPI server.
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
// @host localhost:8080
// @BasePath /api/v1
func setUpSwagger(r *gin.Engine) {
r.GET("/", func(c *gin.Context) {
c.Redirect(http.StatusFound, "/swagger/index.html")
})
r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
// @Summary request ping
// @Description This is detail Description.
// @Accept json
// @Produce json
// @Router /api/v1/ping [get]
// @Success 200 {object} string
func requestPing(c *gin.Context) {
fmt.Println("got ping")
c.JSON(200, gin.H{
"message": "pong",
})
}
Go
복사
# main.go 파일이 있는 위치
swag init
# 만약 main.go 가 루트 위치가 아니라면
swag init -g cmd/main.go # 와 같이 경로 명시
# 서버 실행
go run main.go
# swagger 서버 접속
http://localhost:8080 혹은 http://localhost:8080/swagger/index.html
Bash
복사