이 게시물에서는 Couchbase Go SDK와 함께 Couchbase Analytics를 사용하는 방법을 설명합니다. Couchbase Analytics는 Couchbase Server 6.0에서 사용할 수 있는 새로운 서비스이며, 자세한 내용은 다음에서 확인할 수 있습니다. https://docs.couchbase.com/server/6.0/analytics/introduction.html.
이 글에서는 메모리에 맞지 않을 정도로 큰 실제 데이터 집합을 사용하겠습니다(적어도 제 로컬 컴퓨터에서는). 여기서는 CSV 내보내기 의 2016 뉴욕시 친환경 택시 여정 데이터 세트. 이것은 레코드당 23개의 필드가 있는 약 1,640만 개의 레코드로 구성된 데이터 세트입니다. 프로젝트를 복제하여 애플리케이션을 따라 해볼 수 있습니다. 여기를 클릭하거나
go get github.com/chvck/gocb-택시-분석 . 또한 다음을 실행해야 합니다.
go get ./... 프로젝트를 복제한 경우.
이 데이터는 CSV 파일이므로 가장 먼저 해야 할 일은 데이터를 가져오는 것입니다. 안타깝게도 이 데이터 집합은 비표준 날짜/시간 형식을 사용하므로 작은 스크립트를 사용하여 더 사용하기 쉬운 형식으로 변환해야 합니다. 복제한 경우 프로젝트 를 사용하면 다음과 같이 할 수 있습니다.
|
1 |
go 실행 메인.go --재포맷 --csv /경로/에/택시.csv |
이렇게 하면
2016_그린_택시_트립_데이터.csv 파일을 프로젝트 디렉토리에 추가했습니다. 또한 이 기회에 CSV 헤더를 JSON 친화적으로 변경하고 유형 필드를 항상 녹색으로 설정했습니다(나중에 노란색 택시 데이터 세트도 추가하고 싶을 경우를 대비해). 변환하는 동안 데이터를 직접 가져올 수도 있었지만 이미 cbimport 를 만들 수 있습니다. 다음과 같은 이름의 버킷을 만듭니다. 택시 (고급 버킷 설정에서) 전체 퇴거를 활성화한 다음(이 경우에는 k/v 작업을 실행하지 않으므로 k/v 성능은 크게 중요하지 않음) 실행합니다:
|
1 |
cbimport csv --클러스터 카우치베이스://localhost -u user -p password -b taxis --infer-types -omit-empty -d file:///path/to/2016_Green_Taxi_Trip_Data.csv -l import.log -g green::%vendorID%::#MONO_INCR# |
각 문서에는 다음과 같은 고유 ID가 있습니다.
녹색::1::1000 . 일반적으로 이 두 단계는 데이터가 이미 Couchbase에 보관되어 있으므로 필요하지 않습니다.
카우치베이스 애널리틱스로 작업을 수행하려면 먼저 데이터를 쿼리할 수 있는 데이터 집합을 준비해야 합니다:
|
1 |
만들기 데이터 세트 모든 택시 켜기 택시; |
이 데이터 세트에는 약간의 리소스가 필요합니다. 바쁜 노트북에서 약간 더 작은 데이터 집합으로 실험하고 싶다면 대신 버킷에 있는 문서의 하위 집합만 추적하는 필터링된 데이터 집합을 만들 수 있습니다:
|
1 |
만들기 데이터 세트 모든 택시 켜기 택시 어디 `vendorID` = 1; |
이렇게 하면 3백만 개가 조금 넘는 문서로 구성된 데이터 세트를 얻을 수 있습니다.
데이터 세트 중 하나를 생성한 후에는 다음을 사용하여 데이터 세트 처리를 활성화하여 초기화해야 합니다:
|
1 |
연결 링크 로컬; |
그러면 방금 만든 데이터 세트가 채워지기 시작합니다. UI의 오른쪽 데이터 집합 열에서 데이터 집합 이름 아래에 있는 진행 상황을 확인할 수 있습니다. 데이터 집합이 작성되는 동안 계속 작업할 수 있지만 쿼리를 실행할 때마다 다른 결과가 표시되며 실행 속도가 약간 느려질 수 있습니다.
데이터 분석을 할 예정이므로 몇 가지 조사할 사항을 정리해 두는 것이 좋습니다. 먼저 연간 택시 탑승 횟수를 파악하고 다양한 필터를 적용하여 요금 대비 팁 등을 확인할 수 있는 것이 좋은 출발점이라고 생각합니다.
쿼리에 사용할 기준은 다음과 같습니다:
|
1 |
선택 DATE_PART_STR(pickupDate, "month") AS 기간, COUNT(*) as 카운트 FROM 모든 택시 그룹 BY DATE_PART_STR(pickupDate, "month") 주문 BY 기간; |
이 쿼리는 월을 숫자(1~12)로 추출하고 있습니다. pickupDate 필드로 이동하여 월별 여정 수를 표시합니다. 이 쿼리를 실행하면 3월에 가장 많은 여정이 발생하고 11월에 가장 적은 여정이 발생한다는 것을 알 수 있습니다. 또한 연중 감소 추세도 있습니다. 여름이 다른 계절에 비해 여정이 적을 것이라고 예상했었는데 벌써 뭔가 배운 게 있네요!
이 쿼리는 내 컴퓨터에서 전체 데이터 세트에 대해 약 24초가 걸립니다. 기본 인덱스만 있는 운영 쿼리 서비스(흔히 N1QL이라고도 하지만, 이것이 바로 그 언어)에 대해 동일한 쿼리를 실행하면 쿼리 콘솔에서 600초가 걸립니다(시간 초과). 대규모 데이터 세트에 대한 임시 쿼리의 경우 Couchbase Analytics가 운영 N1QL 쿼리 서비스를 보완하는 좋은 옵션이라는 것을 알 수 있습니다.
Golang 애플리케이션에서 쿼리하기
이제 애널리틱스 데이터 세트가 작동하도록 설정하고 테스트했으므로 Go SDK를 통해 사용할 수 있습니다. 에서 runServer 함수가 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
var err 오류 클러스터, err = gocb.연결(cbConnStr) 만약 err != nil { 패닉("클러스터에 연결하는 동안 오류가 발생했습니다." + err.오류()) } 클러스터.인증(gocb.비밀번호 인증기{ 사용자 이름: cb사용자 이름, 비밀번호: cbPassword, }) _, err = 클러스터.OpenBucket("택시", "") 만약 err != nil { 로그.치명적(err) } 중지 := make(chan os.신호, 1) // 인터럽트 시 서버 중지 신호.알림(중지, os.인터럽트) srv, err := 실행() 만약 err != nil { 로그.치명적(err) } fmt.Println("서버 실행 중", srv.Addr) <-중지 로그.Println("서버 중지") srv.종료(nil) |
이렇게 하면 Couchbase Server에 연결이 생성되고 사용자 이름과 비밀번호를 사용하여 인증됩니다(이러한 속성은 main.go 상단의 속성을 수정하여 사용자 지정할 수 있음). 다음으로 버킷에 대한 연결을 엽니다. 나머지 함수는 웹 서버를 처리합니다. 인터럽트 신호를 수신하는 채널을 만들고 인터럽트 신호가 트리거되면 http 서버를 정상적으로 종료합니다.
명령줄에서 이 데이터를 시각화하고 필터링하는 것은 어렵기 때문에 링크된 코드베이스에 간단한 그래픽 UI를 추가했습니다. 웹 서버는 인덱스 페이지를 제공하고 동적 데이터를 검색할 수 있는 단일 엔드포인트를 노출합니다. 다시 한 번, 이 사용을 실행하려면
go 실행 메인.go 에서 프런트엔드에 액세스할 수 있습니다.
http://localhost:8010 .
동적 데이터 엔드포인트에 대한 핸들러는 다음과 같습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
func 요청 핸들러(w http.응답서 작성기, r *http.요청) { 옵션, err := 프로세스 쿼리 문자열(r.URL.쿼리()) 만약 err != nil { http.오류(w, err.오류(), http.상태 내부 서버 오류) 반환 } q := `선택 DATE_PART_STR(pickupDate, "%s") AS 기간, %s as 집계 FROM 모든 택시` q += ` %s 그룹 BY DATE_PART_STR(pickupDate, "%s") 주문 BY 기간;` q = fmt.Sprintf(q, 옵션.기간, 옵션.집계, 옵션.Where, 옵션.기간) 쿼리 := gocb.새로운 분석 쿼리(q) 결과, err := 클러스터.실행 분석 쿼리(쿼리, 옵션.매개변수) 만약 err != nil { http.오류(w, err.오류(), http.상태 내부 서버 오류) 반환 } 데이터, err := 프로세스 결과(결과) 만약 err != nil { http.오류(w, err.오류(), http.상태 내부 서버 오류) 반환 } 데이터.Where = fmt.Sprintf("%s %s, %v", 옵션.집계, 옵션.Where, 옵션.매개변수) 데이터.쿼리 = fmt.Sprintf("쿼리 = %s, 매개변수 = %v", q, 옵션.매개변수) 데이터.시간 소요 = 결과.메트릭().실행 시간.나노초() js, err := json.마샬(*데이터) 만약 err != nil { http.오류(w, err.오류(), http.상태 내부 서버 오류) 반환 } w.WriteHeader(200) w.헤더().설정("콘텐츠 유형", "application/json") w.쓰기(js) } |
여기서 볼 수 있는 것은 쿼리 문자열을 처리하여 where(및 매개 변수, 자세한 내용은 아래에서 설명합니다), 집계 및 기간을 추출하는 것입니다. 이러한 속성을 통합하여 쿼리를 문자열로 만든 다음 다음을 사용합니다. 새로운 분석 쿼리 를 사용하여 분석 쿼리 . 쿼리를 실행하기 위해 이 쿼리는 클러스터.실행 분석 쿼리 . 그런 다음 결과는 다음과 같이 처리됩니다. 프로세스 결과 를 입력한 후 HTTP 응답을 전송합니다. Where , 시간 소요 그리고 쿼리 속성도 응답에 추가되어 프런트엔드에서 쿼리된 내용을 표시할 수 있습니다.
각 부분을 좀 더 자세히 살펴보겠습니다. 어디 및 집계 매개변수는 프론트엔드에서 이미 올바르게 형식이 지정된 상태로 전달됩니다. 쿼리 문자열은 다음과 같이 보일 수 있습니다.
?기간=시간&월=5&일=14&집계=카운트(*)&어디=요금금액,>,15&어디=팁,<,1
여기서 기간은 쿼리의 세분성(일, 월 또는 연간 전체)을 결정합니다. 하루를 살펴보는 경우 어느 날과 어느 달인지도 알아야 하므로 기간에 따라 월 및 일 매개 변수가 존재하거나 존재하지 않을 수 있습니다. 집계는 연산과 연산을 적용할 필드입니다. 대신 카운트(*) 다음과 같을 수 있습니다. SUM(팁) 또는 AVG(요금) 등...where 매개 변수는 적용할 개별 where 절로, [필드, 연산자, 값] 형식의 배열로 전송됩니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
func whereTimePeriod(기간 문자열, 쿼리 URL.값) 문자열 { 어디 := "" 만약 기간 == "day" { 월 := 쿼리["month"][0] 만약 월 == "1" { 어디 = `pickupDate <= "2016-01-31 23:59:59"` } else 만약 월 == "12" { 어디 = `pickupDate >= "2016-12-01 00:00:00"` } else { monthInt, _ := strconv.파스플로트(월, 64) 어디 = fmt.Sprintf(`pickupDate >= "2016-%02g-01T00:00:00" AND pickupDate <= "2016-%02g-31T23:59:59"`, monthInt, monthInt) } } else 만약 기간 == "시간" { 월 := 쿼리["month"][0] monthInt, _ := strconv.파스플로트(월, 64) 일 := 쿼리["day"][0] dayInt, _ := strconv.파스플로트(일, 64) 어디 = fmt.Sprintf(`pickupDate > "2016-%02g-%02gT00:00:00" AND pickupDate <= "2016-%02g-%02gT23:59:59"`, monthInt, dayInt, monthInt, dayInt) } 반환 어디 } |
그리고 whereTimePeriod 함수는 쿼리 문자열에서 마침표를 추출하여 where 절의 시간 제한 부분을 생성합니다. 기간 매개변수의 값에 따라 다른 로직이 적용되어 where 절을 구성하며, 전체 연도가 필요한 경우 빈 where 절이 반환됩니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
func 프로세스 쿼리 문자열(쿼리 문자열 URL.값) (*쿼리 옵션, 오류) { 집계 := 쿼리 문자열["집계"][0] 기간 := "month" 어디 := "" numParams := 0 var 매개변수 []인터페이스{} 만약 len(쿼리 문자열["기간"]) > 0 { 기간 = 쿼리 문자열["기간"][0] 어디 = whereTimePeriod(기간, 쿼리 문자열) } 에 대한 _, cond := 범위 쿼리 문자열["where"] { numParams++ condParts := 문자열.분할(cond, ",") 만약 len(어디) > 0 { 어디 = fmt.Sprintf("%s 및 %s %s $%d", 어디, condParts[0], condParts[1], numParams) } else { 어디 = fmt.Sprintf("%s %s $%d", condParts[0], condParts[1], numParams) } val, err := strconv.Atoi(condParts[2]) 만약 err != nil { 반환 nil, err } 매개변수 = 추가(매개변수, val) } 만약 len(어디) > 0 { 어디 = fmt.Sprintf("WHERE %s", 어디) } 반환 &쿼리 옵션{ 집계: 집계, Where: 어디, 기간: 기간, 매개변수: 매개변수, }, nil } |
시간 제한 부분이 빌드되면 프론트엔드에서 제공한 각 where 매개변수를 추가할 수 있습니다. 문자열 서식을 사용하여 where 값을 포함하는 대신 쿼리 매개변수를 사용하고 있음을 알 수 있습니다. 이는 SQL 인젝션을 피하기 위한 모범 사례입니다.
쿼리가 실행되면 쿼리가 실행되면 프로세스 결과 함수가 실행되는 것처럼 보입니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
func 프로세스 결과(결과 gocb.분석 결과) (*캘린더데이터, 오류) { var 행 지도[문자열]인터페이스{} var dateParts []float64 var 집계 []float64 에 대한 결과.다음(&행) { 만약 datePart, 확인 := 행["기간"]; 확인 { dateParts = 추가(dateParts, datePart.(float64)) 집계 = 추가(집계, 행["집계"].(float64)) } } 만약 err := 결과.닫기(); err != nil { 반환 nil, err } 반환 &캘린더데이터{ 날짜 부품: dateParts, 집계: 집계, }, nil } |
다음을 사용하여 결과를 반복합니다. 결과.다음(&행) 를 입력하고 각 결과에 대해 결과가 해당하는 기간을 숫자로 가져옵니다. 즉, 시간(0-23), 일(1-31) 또는 월(1-12)을 가져옵니다. 또한 해당 기간에 해당하는 집계된 값도 가져옵니다. 마지막에는 r 결과.닫기() 모든 데이터를 올바르게 읽었는지 확인하기 위해 오류를 검사합니다.
프론트엔드를 사용하면 다양한 필드에 대해 다양한 집계를 쉽게 시도하고, 어디에 절을 적용하고, 데이터를 드릴다운하여 보다 세분화된 보기를 얻을 수 있습니다. 예를 들어 어느 달에 택시가 가장 많은 수익을 창출했는지 알고 싶을 수 있습니다:

5월에 해당하는 점을 클릭하여 자세히 살펴보겠습니다:

주말에 가장 많은 수익이 발생하는 것 같네요. 5월은 날씨가 좋고 주말이 가장 인기가 많기 때문에 여러 명이 함께 관광지를 방문하는 여행이 대부분일까요?

그런 것 같지 않네요! 요금 대 팁 또는 팁이 없는 여정 수 대 팁이 있는 여정 수 등 다른 많은 비교를 할 수 있습니다. 이 데이터세트에는 위치 데이터도 있으므로 픽업 위치의 히트맵을 만드는 등의 작업을 수행할 수 있습니다.
결론
이 예에서는 인덱스를 만들지 않고도 임시적인 간단한 쿼리를 사용하여 다양한 메트릭으로 데이터 집합을 빠르게 분석하는 방법을 살펴봤습니다. Couchbase Analytics가 정식 버전으로 출시되면 이 훌륭한 기능이 Couchbase 플랫폼에 추가될 예정입니다. Golang 개발자는 지금 6.0 베타 버전을 통해 액세스할 수 있습니다.
여러분의 피드백을 기다립니다! 제발 다운로드 지금 바로 카우치베이스 서버 6.0 베타 버전을 사용해 보세요. 카우치베이스 애널리틱스. 다음에서 여러분의 의견을 기다리겠습니다. www.couchbase.com/forums/ 분석에서 Go SDK에 이르기까지 모든 것을 지원합니다.