
Reindexer는 높은 수준의 쿼리 빌더 인터페이스를 갖춘 임베드 가능하고 메모리 내 문서 지향 데이터베이스입니다.
Reindexer의 목표는 복잡한 쿼리를 빠르게 검색하는 것입니다. 우리는 reseam에서 Elasticsearch에 만족하지 않았으며보다 성능있는 대안으로 Reindexer를 만들었습니다.
코어는 C ++로 작성되었으며 응용 프로그램 수준 API가 진행 중입니다.
이 문서는 GO 커넥터와 API에 대해 설명합니다. Reindexer Server 및 HTTP API에 대한 정보를 얻으려면 Reindexer 문서를 참조하십시오.
Reindexer의 두 가지 LTS- 버전이 있습니다 : v3.xx 및 v4.xx
3.xx는 현재 우리의 주류 지점이며 4.xx (릴리스/4 지점)는 실험 래프트 클러스터 및 샤드 지지대를 갖춘 베타 버전입니다. 스토리지는 해당 버전간에 호환되지만 복제 구성은 완전히 다릅니다. 버전 3과 4는 모두 동일한 버그 수정 및 기능 (복제 관련 기능 제외)을 얻습니다.
주요 기능 :
성능은 처음부터 우리의 최우선 과제였으며, 우리는 그것을 꽤 잘 얻을 수 있다고 생각합니다. 벤치 마크에 따르면 Reindexer의 성능은 일반적인 키 가치 데이터베이스와 동등합니다. 단일 CPU 코어에서는 다음과 같습니다.
SELECT * FROM items WHERE id='?'SELECT * FROM items WHERE year > 2010 AND name = 'string' AND id IN (....)SELECT * FROM items WHERE year > 2010 AND name = 'string' JOIN subitems ON ...벤치마킹 결과 및 벤치마킹 Repo의 자세한 내용을 참조하십시오
Reindexer는 가능한 한 작은 기억을 소비하는 것을 목표로합니다. 대부분의 쿼리는 메모리 할당없이 처리됩니다.
이를 달성하기 위해 C ++ 및 GO 레벨 모두에서 몇 가지 최적화가 사용됩니다.
문서와 지수는 조밀 한 바이너리 C ++ 스트러크에 저장되므로 GO의 쓰레기 수집기에는 부하를 부과하지 않습니다.
문자열 복제물이 병합됩니다.
메모리 오버 헤드는 문서 당 약 32 바이트 + 각 검색 인덱스 당 ≈4-16 바이트입니다.
쿼리 실행 후 생성 된 사형화 된 문서의 GO 레벨에 객체 캐시가 있습니다. 향후 쿼리는 사전 예정된 문서를 사용하여 반복 된 사화 및 할당 비용을 줄입니다.
쿼리 인터페이스는 내부 구조 및 버퍼를 재사용하기 위해 sync.Pool 사용합니다. 이러한 기술의 조합으로 Reindexer는 할당없이 대부분의 쿼리를 처리 할 수 있습니다.
Reindexer에는 내부 전체 텍스트 검색 엔진이 있습니다. 전체 텍스트 검색 사용 설명서 및 예제는 여기에 있습니다
Reindexer는 LevelDB를 통해 디스크에 문서를 저장하고로드 할 수 있습니다. 문서는 백그라운드에서 자동으로 대규모 배치에 의해 스토리지 백엔드에 비동기로 쓰여집니다.
네임 스페이스가 만들어지면 모든 문서가 RAM에 저장 되므로이 문서의 쿼리는 전적으로 메모리 모드로 실행됩니다.
다음은 기본 리인덱 서 사용의 완전한 예입니다.
package main
// Import package
import (
"fmt"
"math/rand"
"github.com/restream/reindexer/v3"
// choose how the Reindexer binds to the app (in this case "builtin," which means link Reindexer as a static library)
_ "github.com/restream/reindexer/v3/bindings/builtin"
// OR use Reindexer as standalone server and connect to it via TCP or unix domain socket (if available).
// _ "github.com/restream/reindexer/v3/bindings/cproto"
// OR link Reindexer as static library with bundled server.
// _ "github.com/restream/reindexer/v3/bindings/builtinserver"
// "github.com/restream/reindexer/v3/bindings/builtinserver/config"
)
// Define struct with reindex tags. Fields must be exported - private fields can not be written into reindexer
type Item struct {
ID int64 `reindex:"id,,pk"` // 'id' is primary key
Name string `reindex:"name"` // add index by 'name' field
Articles [] int `reindex:"articles"` // add index by articles 'articles' array
Year int `reindex:"year,tree"` // add sortable index by 'year' field
}
func main () {
// Init a database instance and choose the binding (builtin)
db := reindexer . NewReindex ( "builtin:///tmp/reindex/testdb" )
// OR - Init a database instance and choose the binding (connect to server via TCP sockets)
// Database should be created explicitly via reindexer_tool or via WithCreateDBIfMissing option:
// If server security mode is enabled, then username and password are mandatory
// db := reindexer.NewReindex("cproto://user:[email protected]:6534/testdb", reindexer.WithCreateDBIfMissing())
// OR - Init a database instance and choose the binding (connect to server via unix domain sockets)
// Unix domain sockets are available on the unix systems only (socket file has to be explicitly set on the server's side with '--urpcaddr' option)
// Database should be created explicitly via reindexer_tool or via WithCreateDBIfMissing option:
// If server security mode is enabled, then username and password are mandatory
// db := reindexer.NewReindex("ucproto://user:pass@/tmp/reindexer.socket:/testdb", reindexer.WithCreateDBIfMissing())
// OR - Init a database instance and choose the binding (builtin, with bundled server)
// serverConfig := config.DefaultServerConfig ()
// If server security mode is enabled, then username and password are mandatory
// db := reindexer.NewReindex("builtinserver://user:pass@testdb",reindexer.WithServerConfig(100*time.Second, serverConfig))
// Create new namespace with name 'items', which will store structs of type 'Item'
db . OpenNamespace ( "items" , reindexer . DefaultNamespaceOptions (), Item {})
// Generate dataset
for i := 0 ; i < 100000 ; i ++ {
err := db . Upsert ( "items" , & Item {
ID : int64 ( i ),
Name : "Vasya" ,
Articles : [] int { rand . Int () % 100 , rand . Int () % 100 },
Year : 2000 + rand . Int () % 50 ,
})
if err != nil {
panic ( err )
}
}
// Query a single document
elem , found := db . Query ( "items" ).
Where ( "id" , reindexer . EQ , 40 ).
Get ()
if found {
item := elem .( * Item )
fmt . Println ( "Found document:" , * item )
}
// Query multiple documents
query := db . Query ( "items" ).
Sort ( "year" , false ). // Sort results by 'year' field in ascending order
WhereString ( "name" , reindexer . EQ , "Vasya" ). // 'name' must be 'Vasya'
WhereInt ( "year" , reindexer . GT , 2020 ). // 'year' must be greater than 2020
WhereInt ( "articles" , reindexer . SET , 6 , 1 , 8 ). // 'articles' must contain one of [6,1,8]
Limit ( 10 ). // Return maximum 10 documents
Offset ( 0 ). // from 0 position
ReqTotal () // Calculate the total count of matching documents
// Execute the query and return an iterator
iterator := query . Exec ()
// Iterator must be closed
defer iterator . Close ()
fmt . Println ( "Found" , iterator . TotalCount (), "total documents, first" , iterator . Count (), "documents:" )
// Iterate over results
for iterator . Next () {
// Get the next document and cast it to a pointer
elem := iterator . Object ().( * Item )
fmt . Println ( * elem )
}
// Check the error
if err := iterator . Error (); err != nil {
panic ( err )
}
}C ++에 대한 몇 가지 기본 샘플이 있으며 여기로 이동하십시오.
Query Builder의 대안으로 Reindexer는 SQL 호환 쿼리 인터페이스를 제공합니다. 다음은 SQL 인터페이스 사용 샘플입니다.
...
iterator := db . ExecSQL ( "SELECT * FROM items WHERE name='Vasya' AND year > 2020 AND articles IN (6,1,8) ORDER BY year LIMIT 10" )
...Query Builder 인터페이스가 선호됩니다. 더 많은 기능이 있으며 SQL 인터페이스보다 빠릅니다.
문자열 리터럴은 단일 따옴표로 둘러싸여 있어야합니다.
복합 인덱스는 이중 인용문으로 둘러싸여 있어야합니다.
SELECT * FROM items WHERE " field1+field2 " = ' Vasya '필드 이름이 알파로 시작되지 않으면 '_'또는 '#'는 이중 인용문으로 둘러싸여 있어야합니다.
UPDATE items DROP " 123 " SELECT * FROM ns WHERE " 123 " = ' some_value ' SELECT * FROM ns WHERE " 123abc " = 123 DELETE FROM ns WHERE " 123abc123 " = 111기본 SQL 구문을 통해 간단한 조인이 수행 될 수 있습니다.
SELECT * FROM ns INNER JOIN ns2 ON ns2 . id = ns . fk_id WHERE a > 0왼쪽 네임 스페이스의 조건이있는 조인은 서브 쿼리와 같은 구문을 사용해야합니다.
SELECT * FROM ns WHERE a > 0 AND INNER JOIN ( SELECT * FROM ns2 WHERE b > 10 AND c = 1 ) ON ns2 . id = ns . fk_id하위 쿼리는 또한 where 조건의 일부가 될 수 있습니다.
SELECT * FROM ns WHERE ( SELECT * FROM ns2 WHERE id < 10 LIMIT 0 ) IS NOT NULL SELECT * FROM ns WHERE id = ( SELECT id FROM ns2 WHERE id < 10 ) SELECT * FROM ns WHERE ( SELECT COUNT ( * ) FROM ns2 WHERE id < 10 ) > 18 Reindexer는 3 가지 다른 모드로 실행할 수 있습니다.
embedded (builtin) 리인덱 서는 정적 라이브러리로 응용 프로그램에 포함되어 있으며 별도의 서버 프로세스가 필요하지 않습니다.embedded with server (builtinserver) 은 정적 라이브러리로 Application에 내장되어 있으며 START 서버로 내장됩니다. 이 모드에서 다른 클라이언트는 CPROTO, UCPROTO 또는 HTTP를 통해 응용 프로그램에 연결할 수 있습니다.standalone Reindexer는 독립형 서버로 실행되며 Application은 네트워크 또는 Unix 도메인 소켓을 통해 Reindexer에 연결됩니다.이 모드에서는 Reindexer의 Go-Binding은 Reindexer의 정적 라이브러리에 의존하지 않습니다.
Reindexer 서버를 얻는 가장 간단한 방법은 DockerHub에서 Docker Image를 당기고 실행하는 것입니다.
docker run -p9088:9088 -p6534:6534 -it reindexer/reindexerdockerfile
Reindexer의 핵심은 C ++ 17로 작성되었으며 레벨드B를 스토리지 백엔드로 사용하므로 Reindexer를 설치하기 전에 CMAKE, C ++ 17 도구 체인 및 LevelDB를 설치해야합니다.
Reindexer를 구축하려면 G ++ 8+, Clang 7+ 또는 Mingw64가 필요합니다.
이러한 모드에서 Reindexer의 Go-Binding은 Reindexer의 정적 라이브러리 (핵심, 서버 및 리소스)에 따라 다릅니다.
이 방법은 권장되며 대부분의 시나리오에 적합합니다.
GO.MOD가있는 GO 모듈은 모듈 디렉토리에서 C ++ 라이브러리를 빌드 할 수 없습니다. Go-Binding은 PKG-Config를 사용하여 라이브러리 디렉토리를 감지합니다.
Reindexer의 라이브러리는 소스 또는 패키지 관리자를 통해 사전 제작 된 패키지에서 설치해야합니다.
그런 다음 모듈을 가져옵니다.
go get -a github.com/restream/reindexer/v3 수정 된 Reindexer 소스가 필요한 경우 replace 사용할 수 있습니다.
# Clone reindexer via git. It's also possible to use 'go get -a github.com/restream/reindexer/v3', but it's behavior may vary depending on Go's version
git clone https://github.com/restream/reindexer.git $GOPATH /src/reindexer
bash $GOPATH /src/reindexer/dependencies.sh
# Generate builtin binding
cd $GOPATH /src/reindexer
go generate ./bindings/builtin
# Optional (build builtin server binding)
go generate ./bindings/builtinserver # Go to your app's directory
cd /your/app/path
go get -a github.com/restream/reindexer/v3
go mod edit -replace github.com/restream/reindexer/v3= $GOPATH /src/reindexer이 경우 이동 바인딩은 명시 적 라이브러리 및 Paths 'List를 생성하며 PKG-Config를 사용하지 않습니다.
Go.Mod를 사용하지 않는 경우 소스에서 리인덱 서를 얻고 구축 할 수 있습니다.
export GO111MODULE=off # Disable go1.11 modules
# Go to your app's directory
cd /your/app/path
# Clone reindexer via git. It's also possible to use 'go get -a github.com/restream/reindexer', but it's behavior may vary depending on Go's version
git clone --branch master https://github.com/restream/reindexer.git vendor/github.com/restream/reindexer/v3
# Generate builtin binding
go generate -x ./vendor/github.com/restream/reindexer/v3/bindings/builtin
# Optional (build builtin server binding)
go generate -x ./vendor/github.com/restream/reindexer/v3/bindings/builtinserverGO는 CGO 코드 (Golang/Go#26366)에 대한 적절한 공급원을 지원하지 않지만 Vend를 사용하여 Reindexer의 소스를 공급 업체-디렉토리로 복사 할 수 있습니다.
vend 사용하면 공급 업체 내장에 배치 된 go generate -mod=vendor builtin builtinserver 수 있습니다.
git clone 사용하여 Reindexer의 출처를 청소년 프로젝트에 간단히 복사 할 수도 있습니다.
이 경우 Reindexer의 Go.Mod의 모든 종속성은 적절한 버전으로 수동으로 설치해야합니다.
내부적으로 스트러크는 두 부분으로 나뉩니다.
reindex struct 태그가 표시된 인덱스 필드 reindex 태그가 표시된 인덱스 필드에서만 쿼리가 가능합니다. reindex 태그에는 인덱스 이름, 유형 및 추가 옵션이 포함됩니다.
reindex:"<name>[[,<type>],<opts>]"
name - 색인 이름.type - 인덱스 유형 :hash - Eq에 의해 빠르게 선택되고 일치를 설정합니다. 기본적으로 사용됩니다. 필드별로 느리고 비효율적 인 정렬을 허용합니다.tree - Range, GT 및 LT 매치별로 빠른 선택. hash 인덱스보다 EQ 및 SET MATHES의 경우 약간 느립니다. 필드별로 빠른 분류 결과를 허용합니다.text - 전문 검색 색인. 전체 텍스트 검색의 사용 세부 사항은 여기에 설명되어 있습니다- - 열 색인. 풀 스캔 기술로 구현되었으므로 빠른 선택을 수행 할 수 없습니다. 메모리가 가장 작은 오버 헤드가 있습니다.ttl -TTL 인덱스. 이 인덱스는 지정된 초 양을 만료하는 날짜 필드 (UNIX 타임 스탬프로 저장)를 표현하기에 매우 편리합니다.rtree Dwithin 경기 만 가능합니다. [2]float64 (또는 reindexer.Point ) 필드 유형에 대해서만 허용됩니다. 자세한 내용은 Geometry 하위 섹션을 참조하십시오.opts - 추가 색인 옵션 :pk - 필드는 기본 키의 일부입니다. 구조물에는 pk 가 1 회 이상 있어야합니다.composite - 복합 인덱스를 만듭니다. 필드 유형은 빈 구조물이어야합니다 : struct{} .joined - 필드는 가입 수신자입니다. 필드 유형은 []*SubitemType 이어야합니다.dense - 인덱스 크기를 줄입니다. hash 와 tree 의 경우 고유 키 값 당 8 바이트를 절약합니다. 경우 - 각 요소 당 4-8 바이트를 절약합니다. 선택성이 높지만 선택성이 낮은 tree 및 hash 인덱스의 경우 업데이트 성능을 심각하게 감소시킬 수 있습니다. 또한 CPU 캐시 최적화 부족으로 인해 넓은 풀 스캔 쿼리가 dense - 느리게합니다.sparse -Row (Document)에는 의도적으로 설정된 경우에만 Sparse 인덱스의 값이 포함되어 있습니다. 행에 이러한 유형의 인덱스에 대한 비어있는 (또는 기본값) 레코드가 없습니다 (문서). RAM을 절약 할 수는 있지만 성능이 비용이 들며 일반 인덱스보다 약간 느리게 작동합니다.collate_numeric 숫자 순서에서 값 순서를 제공하는 문자열 색인을 작성하십시오. 필드 유형은 문자열이어야합니다.collate_ascii CATE -Insensive String Index 생성 ASCII와 함께 작동합니다. 필드 유형은 문자열이어야합니다.collate_utf8 CASE 불신성 문자열 인덱스 생성 UTF8에서 작동합니다. 필드 유형은 문자열이어야합니다.collate_custom=<ORDER> - 사용자 정의 주문 문자열 색인을 만듭니다. 필드 유형은 문자열이어야합니다. <ORDER> 는 정렬 순서를 정의하는 글자 시퀀스입니다.linear , quadratic , greene 또는 rstar rtree 지수 구성을위한 알고리즘을 지정하십시오 (기본적으로 rstar ). 자세한 내용은 Geometry 하위 섹션을 참조하십시오.uuid 이 값을 uuid로 저장하십시오. 이것은 문자열보다 UUID에 대한 RAM/네트워크 완성 관점에서 훨씬 더 효과적입니다. UUID에 대한 hash 및 - 유형 만 지원됩니다. 변형 0을 제외하고는 UUID 변형과 함께 사용할 수 있습니다. 일반 인덱스가있는 필드는 무효가되지 않습니다. 조건 is NULL sparse 및 array 인덱스에 의해서만 지원됩니다.
기본적으로 Reindexer는 모든 중첩 스트러크를 스캔하고 네임 스페이스에 필드를 추가합니다 (지정된 인덱스). Indexes 동안 개인 (비수치 필드)을 스캔하는 동안 reindex:"-" 및 json:"-" 으로 태그가 지정된 필드가 건너 뜁니다.
type Actor struct {
Name string `reindex:"actor_name"`
Age int `reindex:"age"`
}
type BaseItem struct {
ID int64 `reindex:"id,hash,pk"`
UUIDValue string `reindex:"uuid_value,hash,uuid"`
}
type ComplexItem struct {
BaseItem // Index fields of BaseItem will be added to reindex
Actor [] Actor // Index fields ("name" and "age") of Actor will be added to reindex as array-indexes
Name string `reindex:"name"` // Hash-index for "name"
Year int `reindex:"year,tree"` // Tree-index for "year"
Value int `reindex:"value,-"` // Store(column)-index for "value"
Metainfo int `json:"-"` // Field "MetaInfo" will not be stored in reindexer
Parent * Item `reindex:"-"` // Index fields of "Parent" will NOT be added to reindex and all of the "Parent" exported content will be stored as non-indexed data
ParentHidden * Item `json:"-"` // Indexes and fields of "ParentHidden" will NOT be added to reindexer
privateParent * Item // Indexes and fields of "ParentHidden" will NOT be added to reindexer (same as with `json:"-"`)
AnotherActor Actor `reindex:"actor"` // Index fields of "AnotherActor" will be added to reindexer with prefix "actor." (in this example two indexes will be created: "actor.actor_name" and "actor.age")
}Reindexer는 필드 (결합 된 네임 스페이스의 중첩 및 필드 포함) 또는 오름차순 또는 내림차순으로 문서를 정렬 할 수 있습니다.
비 인덱스 필드로 정렬하려면 모든 값은 서로 변환 할 수 있어야합니다. 즉, 동일한 유형을 가지거나 숫자 유형 중 하나 여야합니다 ( bool , int , int64 또는 float ).
정렬 표현식은 다음을 포함 할 수 있습니다.
bool , int , int64 , float 또는 string 유형의 필드 및 인덱스 이름 (결합 된 네임 스페이스의 중첩 필드 및 필드 포함). 모든 값은 선행 및 마무리 공간을 무시하는 숫자로 변환 할 수 있어야합니다.rank() , abs() 및 ST_Distance() ;+ , - (단수 및 이진), * 및 / . 필드 이름 뒤에 + 가있는 경우 복합 인덱스 이름을 구별하기 위해 공간으로 분리해야합니다. 결합 joined_namespace.field 네임 스페이스의 필드는 다음과 같이 작성해야합니다.
Abs() 인수의 절대 값을 의미합니다.
Rank() 풀 텍스트 순위 일치를 의미하며 FullText Query에서만 적용됩니다.
ST_Distance() 지오메트리 포인트 사이의 거리를 의미합니다 (Geometry 하위 섹션 참조). 포인트는 현재 또는 결합 된 네임 스페이스 또는 고정 점에서 열이 될 수 있습니다 ST_GeomFromText('point(1 -3)')
SQL 쿼리에서 정렬 식을 인용해야합니다.
type Person struct {
Name string `reindex:"name"`
Age int `reindex:"age"`
}
type City struct {
Id int `reindex:"id"`
NumberOfPopulation int `reindex:"population"`
Center reindexer. Point `reindex:"center,rtree,linear"`
}
type Actor struct {
ID int `reindex:"id"`
PersonData Person `reindex:"person"`
Price int `reindex:"price"`
Description string `reindex:"description,text"`
BirthPlace int `reindex:"birth_place_id"`
Location reindexer. Point `reindex:"location,rtree,greene"`
}
... .
query := db . Query ( "actors" ). Sort ( "id" , true ) // Sort by field
... .
query = db . Query ( "actors" ). Sort ( "person.age" , true ) // Sort by nested field
... .
// Sort by joined field
// Works for inner join only, when each item from left namespace has exactly one joined item from right namespace
query = db . Query ( "actors" ).
InnerJoin ( db . Query ( "cities" )). On ( "birth_place_id" , reindexer . EQ , "id" ).
Sort ( "cities.population" , true )
... .
// Sort by expression:
query = db . Query ( "actors" ). Sort ( "person.age / -10 + price / 1000 * (id - 5)" , true )
... .
query = db . Query ( "actors" ). Where ( "description" , reindexer . EQ , "ququ" ).
Sort ( "rank() + id / 100" , true ) // Sort with fulltext rank
... .
// Sort by geometry distance
query = db . Query ( "actors" ).
Join ( db . Query ( "cities" )). On ( "birth_place_id" , reindexer . EQ , "id" ).
SortStPointDistance ( cities . center , reindexer. Point { 1.0 , - 3.0 }, true ).
SortStFieldDistance ( "location" , "cities.center" , true )
... .
// In SQL query:
iterator := db . ExecSQL ( "SELECT * FROM actors ORDER BY person.name ASC" )
... .
iterator := db . ExecSQL ( "SELECT * FROM actors WHERE description = 'ququ' ORDER BY 'rank() + id / 100' DESC" )
... .
iterator := db . ExecSQL ( "SELECT * FROM actors ORDER BY 'ST_Distance(location, ST_GeomFromText( ' point(1 -3) ' ))' ASC" )
... .
iterator := db . ExecSQL ( "SELECT * FROM actors ORDER BY 'ST_Distance(location, cities.center)' ASC" )이와 같이 사용자 정의 정렬 순서를 설정할 수도 있습니다.
type SortModeCustomItem struct {
ID int `reindex:"id,,pk"`
InsItem string `reindex:"item_custom,hash,collate_custom=a-zA-Z0-9"`
}또는 이렇게
type SortModeCustomItem struct {
ID int `reindex:"id,,pk"`
InsItem string `reindex:"item_custom,hash,collate_custom=АаБбВвГгДдЕеЖжЗзИиКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭ-ЯAaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0-9ЁёЙйэ-я"`
}이 목록의 첫 번째 캐릭터는 가장 우선 순위가 가장 높으며 마지막 캐릭터의 우선 순위는 가장 작은 캐릭터입니다. 정렬 알고리즘이 첫 번째 문자로 시작하는 항목을 다른 문자보다 먼저 배치한다는 것을 의미합니다. 일부 캐릭터가 건너 뛰면 우선 순위는 일반적인 값을 가질 수 있습니다 (목록의 문자에 따라).
문자열 필드 조건에서 간단한 검색 텍스트 패턴의 LIKE 사용할 수 있습니다. 패턴과 일치하는 문자열을 찾습니다. 패턴 _ 에서는 모든 숯을 의미하고 % 모든 숯 순서를 의미합니다.
Go example:
query := db . Query ( "items" ).
Where ( "field" , reindexer . LIKE , "pattern" )SQL 예 :
SELECT * FROM items WHERE fields LIKE ' pattern ''me_t'는 'meet', 'meat', 'melt'등에 해당합니다.
주의 : 스캔 방법을 사용합니다. 디버그 목적으로 또는 다른 좋은 선택적 조건이있는 쿼리 내에 사용될 수 있습니다.
일반적으로 합리적인 속도로 전체 텍스트 검색의 경우 FullText 색인을 사용하는 것이 좋습니다.
업데이트 쿼리는 네임 스페이스의 기존 항목을 수정하는 데 사용됩니다. 기존 필드 업데이트, 새 필드 추가 및 기존 비 인덱스 필드를 삭제하는 여러 종류의 업데이트 쿼리가 있습니다.
SQL-Syntax를 업데이트하십시오
UPDATE nsName
SET field1 = value1, field2 = value2, ..
WHERE condition;+, -, /, * 및 브래킷과 함께 산술 표현식을 사용할 수도 있습니다.
UPDATE NS SET field1 = field2 + field3 - (field4 + 5 ) / 2 now() , sec() 및 serial() 과 같은 함수를 포함합니다. Golang Code의 표현식을 사용하려면 SetExpression() 메소드를 Set() 대신 호출해야합니다.
배열 필드를 비우기 위해
UPDATE NS SET arrayfield = [] WHERE id = 100널로 설정하십시오
UPDATE NS SET field = NULL WHERE id > 100비 인덱스 필드의 경우 값을 다른 유형의 값으로 설정하면 완전히 대체됩니다. 인덱스 된 필드의 경우 인접한 유형 (적분 유형 및 bool), 숫자 문자열 ( "123456")에서 통합 유형 및 뒤로 변환 할 수 있습니다. 색인 된 필드를 NULL로 설정하여 기본값으로 재설정합니다.
기존 품목에 새 필드를 추가 할 수 있습니다.
UPDATE NS SET newField = ' Brand new! ' WHERE id > 100그리고 이와 같은 복잡한 중첩 경로로 새로운 필드를 추가하십시오.
UPDATE NS SET nested . nested2 . nested3 . nested4 .newField = ' new nested field! ' WHERE id > 100Object Nested4의 멤버로서 중첩, Nested2, Nested3, Nested4 및 Newfield의 다음 중첩 된 물체를 만듭니다.
Golang 코드에서 업데이트 쿼리 사용 예 :
db . Query ( "items" ). Where ( "id" , reindexer . EQ , 40 ). Set ( "field1" , values ). Update ()Reindexer를 사용하면 객체 필드를 업데이트하고 추가 할 수 있습니다. 객체는 구조물, 맵 또는 바이트 배열 (JSON 버전의 객체 표현)으로 설정할 수 있습니다.
type ClientData struct {
Name string `reindex:"name" json:"name"`
Age int `reindex:"age" json:"age"`
Address int `reindex:"year" json:"year"`
Occupation string `reindex:"occupation" json:"occupation"`
TaxYear int `reindex:tax_year json:"tax_year"`
TaxConsultant string `reindex:tax_consultant json:"tax_consultant"`
}
type Client struct {
ID int `reindex:"id" json:"id"`
Data ClientData `reindex:"client_data" json:"client_data"`
...
}
clientData := updateClientData ( clientId )
db . Query ( "clients" ). Where ( "id" , reindexer . EQ , 100 ). SetObject ( "client_data" , clientData ). Update () 이 경우 Golang의 Map String으로 만 키로 작동 할 수 있습니다. map[string]interface{} 는 완벽한 선택입니다.
SQL 명령문 별 객체 필드 업데이트 :
UPDATE clients SET client_data = { " Name " : " John Doe " , " Age " : 40 , " Address " : " Fifth Avenue, Manhattan " , " Occupation " : " Bank Manager " , " TaxYear " : 1999 , " TaxConsultant " : " Jane Smith " } WHERE id = 100 ;기존 비 인덱스 필드를 삭제하는 쿼리의 SQL-Syntax 업데이트 :
UPDATE nsName
DROP field1, field2, ..
WHERE condition; db . Query ( "items" ). Where ( "id" , reindexer . EQ , 40 ). Drop ( "field1" ). Update ()Reindexer 업데이트 메커니즘을 사용하면 배열 필드를 수정할 수 있습니다. 기존 배열의 특정 항목을 수정하거나 전체 필드를 교체 할 수 있습니다.
항목 구독 운영자 구문을 업데이트하려면 다음과 같습니다.
UPDATE NS SET array[ * ].prices[ 0 ] = 9999 WHERE id = 5 여기서 * 모든 항목을 의미합니다.
전체 배열을 업데이트하려면 다음이 사용됩니다.
UPDATE NS SET prices = [ 999 , 1999 , 2999 ] WHERE id = 9이 구문을 사용하여 모든 비 인덱스 필드를 배열로 쉽게 변환 할 수 있습니다.
Reindexer는 객체 배열의 항목을 업데이트 할 수 있습니다.
UPDATE NS SET extra . objects [ 0 ] = { " Id " : 0 , " Description " : " Updated! " } WHERE id = 9또한 이렇게
db . Query ( "clients" ). Where ( "id" , reindexer . EQ , 100 ). SetObject ( "extra.objects[0]" , updatedValue ). Update ()Reindexer는 이종 어레이를 지원합니다.
UPDATE NS SET info = [ " hi " , " bro " , 111 , 2 . 71 ] WHERE id = 9 q := DB . Query ( ns ). Where ( "id" , reindexer . EQ , 1 ). Set ( "array" , [] interface {}{ "whatsup" , 777 , "bro" })
res , err := q . Update (). FetchAll ()인덱스 배열 필드는 인덱스 유형으로만 변환 할 수있는 값을 지원합니다. 저장되면, 이러한 값은 변환으로 인해 정밀도가 변경 될 수 있습니다.
UPDATE NS SET prices_idx = [ 11 , ' 2 ' , 3 ]색인 별 항목을 제거하려면 다음을 수행해야합니다.
UPDATE NS DROP array[ 5 ]기존 배열에 항목을 추가하려면 다음 구문이 지원됩니다.
UPDATE NS SET integer_array = integer_array || [ 5 , 6 , 7 , 8 ]그리고
UPDATE NS SET integer_array = [ 1 , 2 , 3 , 4 , 5 ] || integer_array 첫 번째는 integer_array 의 끝에 요소를 추가하고 두 번째는 5 개의 항목을 앞면에 추가합니다. 이 코드를 Golang SetExpression() 에서 작동 시키려면 Set() 대신 사용해야합니다.
기존 배열로 값으로 항목을 제거하려면 다음 구문이 지원됩니다.
UPDATE NS SET integer_array = array_remove(integer_array, [ 5 , 6 , 7 , 8 ])그리고
UPDATE NS SET integer_array = array_remove_once(integer_array, [ 5 , 6 , 7 , 8 , 6 ]) 첫 번째는 integer_array 에서 나열된 값의 모든 발생을 제거하며, 두 번째는 발견 된 첫 번째 발생 만 삭제합니다. 이 코드를 Golang SetExpression() 에서 작동 시키려면 Set() 대신 사용해야합니다. 하나의 값을 제거 해야하는 경우 사각형 브래킷 [5] 또는 간단한 값 5 사용할 수 있습니다.
UPDATE NS SET integer_array = array_remove(integer_array, [ 5 ]) update ns set integer_array = array_remove(integer_array, 5 )제거 명령을 배열과 결합 할 수 있습니다.
UPDATE NS SET integer_array = array_remove_once(integer_array, [ 5 , 6 , 7 , 8 ]) || [ 1 , 2 , 3 ]또한 이렇게
db . Query ( "main_ns" ). SetExpression ( "integer_array" , "array_remove(integer_array, [5,6,7,8]) || [1,2,3]" ). Update ()첫 번째 필드의 값에서 두 번째 필드의 값을 제거 할 수 있습니다. 또한 새 값 등을 추가합니다. 참고 : 명령의 첫 번째 매개 변수는 배열/필드 어레이가 될 것으로 예상됩니다. 두 번째 매개 변수는 배열/스칼라/필드 어레이/필드 스칼라 일 수 있습니다. 값 호환성/전환 가능성이 필요합니다
UPDATE NS SET integer_array = [ 3 ] || array_remove(integer_array, integer_array2) || integer_array3 || array_remove_once(integer_array, [ 8 , 1 ]) || [ 2 , 4 ] UPDATE NS SET integer_array = array_remove(integer_array, integer_array2) || array_remove(integer_array, integer_array3) || array_remove_once(integer_array, [ 33 , 777 ]) db . Query ( "main_ns" ). SetExpression ( "integer_array" , "[3] || array_remove(integer_array, integer_array2) || integer_array3 || array_remove(integer_array, [8,1]) || [2,4]" ). Update () Reindexer는 거래를 지원합니다. 트랜잭션은 원자 네임 스페이스 업데이트를 수행합니다. 동기식 및 비동기 트랜잭션이 있습니다. 트랜잭션 방법을 시작하려면 db.BeginTx() 사용됩니다. 이 메소드는 트랜잭션 객체를 생성하는데, 이는 응용 프로그램에 대한 일반적인 업데이트/upsert/삽입/삭제를 제공합니다. RPC 클라이언트의 경우 트랜잭션 수 제한이 있습니다. 각 연결은 동시에 1024 개 이상의 공개 트랜잭션을 가질 수 없습니다.
// Create new transaction object
tx , err := db . BeginTx ( "items" );
if err != nil {
panic ( err )
}
// Fill transaction object
tx . Upsert ( & Item { ID : 100 })
tx . Upsert ( & Item { ID : 101 })
tx . Query (). WhereInt ( "id" , reindexer . EQ , 102 ). Set ( "Name" , "Petya" ). Update ()
// Apply transaction
if err := tx . Commit (); err != nil {
panic ( err )
}벌크 레코드의 속도를 높이기 위해 비동기 모드를 사용할 수 있습니다.
// Create new transaction object
tx , err := db . BeginTx ( "items" );
if err != nil {
panic ( err )
}
// Prepare transaction object async.
tx . UpsertAsync ( & Item { ID : 100 }, func ( err error ) {})
tx . UpsertAsync ( & Item { ID : 100 }, func ( err error ) {})
// Wait for async operations done, and apply transaction.
if err := tx . Commit (); err != nil {
panic ( err )
} UpsertAsync 의 두 번째 인수는 완료 함수이며 서버 응답을받은 후에 호출됩니다. 또한 준비 프로세스 중에 오류가 발생하면 tx.Commit 에 오류가 반환됩니다. 따라서 tx.Commit 에 의해 반환 된 오류를 확인하는 것으로 충분합니다. 모든 데이터가 성공적으로 커밋되었는지 확인했습니다.
거래 변경량에 따라 두 가지 가능한 커밋 전략이 있습니다.
커밋 전략을 선택하기위한 데이터 양은 네임 스페이스 구성에서 선택할 수 있습니다. struct DBNamespacesConfig (spectioner.go)의 StartCopyPolicyTxSize 및 TxSizeToAlwaysCopy CopyPolicyMultiplier 확인하십시오.
트랜잭션 크기가 TxSizeToAlwaysCopy 미만인 경우, Reindexer는 추가 휴리스틱을 사용하고 네임 스페이스에 표시되는 쿼리가없는 경우 네임 스페이스 복사를 피하려고합니다. 경우에 따라이 휴리스틱은 선택 대기 시간을 증가시킬 수 있으므로 REINDEXER_NOTXHEURISTIC env 변수를 비어 있지 않은 값으로 설정하여 비활성화 될 수 있습니다.
tx.Query("ns").Exec() ... ;Reindexer는 여러 네임 스페이스에서 문서를 단일 결과로 연결할 수 있습니다.
type Actor struct {
ID int `reindex:"id"`
Name string `reindex:"name"`
IsVisible bool `reindex:"is_visible"`
}
// Fields, marked with 'joined' must also be exported - otherwise reindexer's binding will not be able to put data in those fields
type ItemWithJoin struct {
ID int `reindex:"id"`
Name string `reindex:"name"`
ActorsIDs [] int `reindex:"actors_ids"`
ActorsNames [] int `reindex:"actors_names"`
Actors [] * Actor `reindex:"actors,,joined"`
}
... .
query := db . Query ( "items_with_join" ). Join (
db . Query ( "actors" ).
WhereBool ( "is_visible" , reindexer . EQ , true ),
"actors"
). On ( "actors_ids" , reindexer . SET , "id" )
it := query . Exec ()이 예에서 Reindexer는 후드 아래의 반사를 사용하여 액터 슬라이스를 만들고 액터 구조를 복사합니다.
가입 쿼리는 (기본적으로) Or 운영자 Not 연결된 And 에 대해 1에서 여러 가지 On 가질 수 있습니다.
query := db . Query ( "items_with_join" ).
Join (
db . Query ( "actors" ).
WhereBool ( "is_visible" , reindexer . EQ , true ),
"actors" ).
On ( "actors_ids" , reindexer . SET , "id" ).
Or ().
On ( "actors_names" , reindexer . SET , "name" ) InnerJoin 두 네임 스페이스의 결합 필드에 일치하는 두 개의 네임 스페이스의 데이터를 결합합니다. LeftJoin LeftJoin 키워드의 왼쪽 네임 스페이스에서 모든 유효한 항목을 오른쪽 테이블의 값과 함께 또는 일치하는 항목이 존재하지 않는 경우 아무것도 반환합니다. Join LeftJoin 의 별칭입니다.
InnerJoins Where 절에서 조건으로 사용될 수 있습니다.
query1 := db . Query ( "items_with_join" ).
WhereInt ( "id" , reindexer . RANGE , [] int { 0 , 100 }).
Or ().
InnerJoin ( db . Query ( "actors" ). WhereString ( "name" , reindexer . EQ , "ActorName" ), "actors" ).
On ( "actors_ids" , reindexer . SET , "id" ).
Or ().
InnerJoin ( db . Query ( "actors" ). WhereInt ( "id" , reindexer . RANGE , [] int { 100 , 200 }), "actors" ).
On ( "actors_ids" , reindexer . SET , "id" )
query2 := db . Query ( "items_with_join" ).
WhereInt ( "id" , reindexer . RANGE , [] int { 0 , 100 }).
Or ().
OpenBracket ().
InnerJoin ( db . Query ( "actors" ). WhereString ( "name" , reindexer . EQ , "ActorName" ), "actors" ).
On ( "actors_ids" , reindexer . SET , "id" ).
InnerJoin ( db . Query ( "actors" ). WhereInt ( "id" , reindexer . RANGE , [] int { 100 , 200 }), "actors" ).
On ( "actors_ids" , reindexer . SET , "id" ).
CloseBracket ()
query3 := db . Query ( "items_with_join" ).
WhereInt ( "id" , reindexer . RANGE , [] int { 0 , 100 }).
Or ().
InnerJoin ( db . Query ( "actors" ). WhereInt ( "id" , reindexer . RANGE , [] int { 100 , 200 }), "actors" ).
On ( "actors_ids" , reindexer . SET , "id" ).
Limit ( 0 ) 일반적으로 Or 운영자는 Where 에 대한 단락을 구현합니다. 이전 조건이 참이면 다음 조건은 평가되지 않습니다. 그러나 InnerJoin 의 경우 query1 (위의 예에서)에서 두 개의 InnerJoin 조건은 WhereInt 의 결과에도 불구하고 평가됩니다. InnerJoin (위의 예에서 query3 )의 일부로 Limit(0) 데이터에 결합되지 않습니다. 조건을 확인하기 위해 필터처럼 작동합니다.
Reindexer는 ANTI JOIN SQL Construction을 지원하지 않지만 조인이있는 논리적 작업을 지원합니다. 실제로 NOT (INNER JOIN ...) ANTI JOIN 과 완전히 같습니다.
query := db . Query ( "items_with_join" ).
Not ().
OpenBracket (). // Brackets are essential here for NOT to work
InnerJoin (
db . Query ( "actors" ).
WhereBool ( "is_visible" , reindexer . EQ , true ),
"actors" ).
On ( "id" , reindexer . EQ , "id" )
CloseBracket () SELECT * FROM items_with_join
WHERE
NOT (
INNER JOIN (
SELECT * FROM actors WHERE is_visible = true
) ON items_with_join . id = actors . id
) 반사 사용을 피하기 위해 Item Joinable 인터페이스를 구현할 수 있습니다. 구현 된 경우 Reindexer는 느린 반사 기반 구현 대신에이를 사용합니다. 이는 전체 성능을 10-20%증가시키고 할당량을 줄입니다.
// Joinable interface implementation.
// Join adds items from the joined namespace to the `ItemWithJoin` object.
// When calling Joinable interface, additional context variable can be passed to implement extra logic in Join.
func ( item * ItemWithJoin ) Join ( field string , subitems [] interface {}, context interface {}) {
switch field {
case "actors" :
for _ , joinItem := range subitems {
item . Actors = append ( item . Actors , joinItem .( * Actor ))
}
}
}현재 쿼리에 포함 된 다른 쿼리 (하위 쿼리)의 결과에 조건을 적용 할 수 있습니다. 조건은 하위 퀘스트의 결과로 될 수 있습니다.
query := db . Query ( "main_ns" ).
WhereQuery ( db . Query ( "second_ns" ). Select ( "id" ). Where ( "age" , reindexer . GE , 18 ), reindexer . GE , 100 )또는 기본 쿼리의 네임 스페이스 필드와 하위 퀘스트의 결과 사이 :
query := db . Query ( "main_ns" ).
Where ( "id" , reindexer . EQ , db . Query ( "second_ns" ). Select ( "id" ). Where ( "age" , reindexer . GE , 18 )) 하위 쿼리의 결과는 Select 메소드로 가리키는 특정 필드 일 수 있습니다 (이 경우 단일 필드 필터를 설정해야합니다).
query1 := db . Query ( "main_ns" ).
WhereQuery ( db . Query ( "second_ns" ). Select ( "id" ). Where ( "age" , reindexer . GE , 18 ), reindexer . GE , 100 )
query2 := db . Query ( "main_ns" ).
Where ( "id" , reindexer . EQ , db . Query ( "second_ns" ). Select ( "id" ). Where ( "age" , reindexer . GE , 18 )) 또는 ReqTotal 또는 CachedTotal 방법에 의해 요구되는 하위 쿼리에 만족하는 항목의 수 :
query1 := db . Query ( "main_ns" ).
WhereQuery ( db . Query ( "second_ns" ). Where ( "age" , reindexer . GE , 18 ). ReqTotal (), reindexer . GE , 100 )
query2 := db . Query ( "main_ns" ).
Where ( "id" , reindexer . EQ , db . Query ( "second_ns" ). Where ( "age" , reindexer . GE , 18 ). CachedTotal ())또는 집계 :
query1 := db . Query ( "main_ns" ).
WhereQuery ( db . Query ( "second_ns" ). Where ( "age" , reindexer . GE , 18 ). AggregateMax ( "age" ), reindexer . GE , 33 )
query2 := db . Query ( "main_ns" ).
Where ( "age" , reindexer . GE , db . Query ( "second_ns" ). Where ( "age" , reindexer . GE , 18 ). AggregateAvg ( "age" )) Min , Max , Avg , Sum , Count 및 CountCached Agregation 만 허용됩니다. 서브 쿼리는 동시에 여러 집계를 포함 할 수 없습니다.
하위 쿼리는 동일한 네임 스페이스 또는 다른 네임 스페이스에 적용될 수 있습니다.
하위 쿼리에는 다른 하위 쿼리, 가입 또는 병합을 포함 할 수 없습니다.
항목 중 하나 이상이 하위 쿼리에 만족하는지 확인하려면, 또는 ANY 상태 EMPTY 사용할 수 있습니다.
query1 := db . Query ( "main_ns" ).
WhereQuery ( db . Query ( "second_ns" ). Where ( "age" , reindexer . GE , 18 ), reindexer . ANY , nil )
query2 := db . Query ( "main_ns" ).
WhereQuery ( db . Query ( "second_ns" ). Where ( "age" , reindexer . LE , 18 ), reindexer . EMPTY , nil )문서는 여러 필드를 기본 키로 가질 수 있습니다. 이 기능을 가능하게하려면 Composite Index를 Struct에 추가하십시오. 복합 인덱스는 여러 필드를 포함하는 인덱스이며 여러 별도의 인덱스 대신 사용할 수 있습니다.
type Item struct {
ID int64 `reindex:"id"` // 'id' is a part of a primary key
SubID int `reindex:"sub_id"` // 'sub_id' is a part of a primary key
// Fields
// ....
// Composite index
_ struct {} `reindex:"id+sub_id,,composite,pk"`
}또는
type Item struct {
ID int64 `reindex:"id,-"` // 'id' is a part of primary key, WITHOUT personal searchable index
SubID int `reindex:"sub_id,-"` // 'sub_id' is a part of a primary key, WITHOUT a personal searchable index
SubSubID int `reindex:"sub_sub_id,-"` // 'sub_sub_id' is a part of a primary key WITHOUT a personal searchable index
// Fields
// ....
// Composite index
_ struct {} `reindex:"id+sub_id+sub_sub_id,,composite,pk"`
}또한 복합 인덱스는 여러 필드로 결과를 정렬하는 데 유용합니다.
type Item struct {
ID int64 `reindex:"id,,pk"`
Rating int `reindex:"rating"`
Year int `reindex:"year"`
// Composite index
_ struct {} `reindex:"rating+year,tree,composite"`
}
...
// Sort query results by rating first, then by year
query := db . Query ( "items" ). Sort ( "rating+year" , true )
// Sort query results by rating first, then by year, and put item where rating == 5 and year == 2010 first
query := db . Query ( "items" ). Sort ( "rating+year" , true ,[] interface {}{ 5 , 2010 }) 복합 인덱스에 대한 쿼리를 위해 쿼리 빌더의 [] interface {}을 .WhereComposite
// Get results where rating == 5 and year == 2010
query := db . Query ( "items" ). WhereComposite ( "rating+year" , reindexer . EQ ,[] interface {}{ 5 , 2010 }) 정기적 인 (가상도) 복합 인덱스의 모든 필드를 인덱싱해야합니다. 즉, 복합 인덱스 rating+year 만들 수 있으려면 먼저 raiting 과 year 위해 어떤 종류의 인덱스를 만들어야합니다.
type Item struct {
ID int64 `reindex:"id,,pk"`
Rating int `reindex:"rating,-"` // this field must be indexed (using index type '-' in this example)
Year int `reindex:"year"` // this field must be indexed (using index type 'hash' in this example)
_ struct {} `reindex:"rating+year,tree,composite"`
}Reindexer는 집계 된 결과를 검색 할 수 있습니다. 현재 카운트, 카운트 캐싱, 평균, 합계, 최소, 최대, 패싯 및 별개의 집계가 지원됩니다.
Count - Querie의 조건을 충족하는 총 문서 수 받기CountCached Querie의 조건을 충족하는 총 문서 수를 얻으십시오. 결과 값은 캐시로 만들어지고 카운트 캐시 집계로 다른 쿼리에 의해 재사용 될 수 있습니다.AggregateMax 최대 필드 값을 얻습니다AggregateMin 최소 필드 값을 얻으십시오AggregateSum 합계 필드 값을 얻습니다AggregateAvg 평균 필드 값을 얻습니다AggregateFacet -Get Fields FASET 값Distinct - 필드의 고유 한 가치 목록 얻기 응집력을 지원하기 위해 Query 쿼리 실행 전에 메소드 AggregateAvg , AggregateSum , AggregateMin , AggregateMax , AggregateFacet 및 Distinct 의 방법을 가지고 있습니다. Query 실행 전에 호출해야합니다. 이것은 Reindexer에게 데이터 집계를 계산하도록 요청합니다. 집계 패싯은 여러 데이터 열에 적용 할 수 있으며 그 결과는 모든 데이터 열 또는 '카운트'에 의해 정렬되고 오프셋 및 제한으로 차단 될 수 있습니다. 이 기능성을 지원하기 위해 AggregateFacet 메소드 Sort , Limit 및 Offset 있는 AggregationFacetRequest 반환합니다.
MERGE가있는 쿼리는 기본 쿼리에서 병합 된 하위 쿼리에 집계를 적용합니다. 하위 Queries는 자체 집계를 가질 수 없습니다. 병합 쿼리에 대한 사용 가능한 집계는 다음과 같습니다. count, countcached, sum, min and max.
집계 결과를 얻으려면 Iterator 메소드 AggResults 있습니다. 쿼리 실행 후에 사용할 수 있으며 결과 조각을 반환합니다.
price 및 name 별 집계 items 에 대한 코드 예제
query := db . Query ( "items" )
query . AggregateMax ( "price" )
query . AggregateFacet ( "name" , "price" ). Sort ( "name" , true ). Sort ( "count" , false ). Offset ( 10 ). Limit ( 100 )
iterator := query . Exec ()
// Check the error
if err := iterator . Error (); err != nil {
panic ( err )
}
defer iterator . Close ()
aggMaxRes := iterator . AggResults ()[ 0 ]
if aggMaxRes . Value != nil {
fmt . Printf ( "max price = %d n " , * aggMaxRes . Value )
} else {
fmt . Println ( "no data to aggregate" )
}
aggFacetRes := iterator . AggResults ()[ 1 ]
fmt . Printf ( "'name' 'price' -> count" )
for _ , facet := range aggFacetRes . Facets {
fmt . Printf ( "'%s' '%s' -> %d" , facet . Values [ 0 ], facet . Values [ 1 ], facet . Count )
} query := db . Query ( "items" )
query . Distinct ( "name" ). Distinct ( "price" )
iterator := query . Exec ()
// Check the error
if err := iterator . Error (); err != nil {
panic ( err )
}
defer iterator . Close ()
aggResults := iterator . AggResults ()
distNames := aggResults [ 0 ]
fmt . Println ( "names:" )
for _ , name := range distNames . Distincts {
fmt . Println ( name )
}
distPrices := aggResults [ 1 ]
fmt . Println ( "prices:" )
for _ , price := range distPrices . Distincts {
fmt . Println ( price )
} 집계 된 FACET 의 필드에 의한 정렬 SQL 버전에는 구별이 있습니다.
SELECT FACET(name, price ORDER BY " name " ASC , " count " DESC ) FROM items일치하는 값에 동일한 인덱스 위치가있을 때 LeIndexer는 배열 필드에서 데이터를 검색 할 수 있습니다. 예를 들어, 우리는 다양한 구조를 가지고 있습니다.
type Elem struct {
F1 int `reindex:"f1"`
F2 int `reindex:"f2"`
}
type A struct {
Elems [] Elem
}이 배열에서 값을 검색하려는 일반적인 시도
db . Query ( "Namespace" ). Where ( "f1" , EQ , 1 ). Where ( "f2" , EQ , 2 ) f1 은 1과 f2 Elem[] 2와 같다.
EqualPosition Function을 사용하면 동일한 인덱스가있는 배열 필드에서 검색 할 수 있습니다. 다음과 같은 쿼리 :
db . Query ( "Namespace" ). Where ( "f1" , reindexer . GE , 5 ). Where ( "f2" , reindexer . EQ , 100 ). EqualPosition ( "f1" , "f2" )또는
SELECT * FROM Namespace WHERE f1 >= 5 AND f2 = 100 EQUAL_POSITION(f1,f2); f1 이 5와 f2 인 equal 배열 인덱스가있는 배열 Elem[] 의 모든 항목을 찾을 수 있습니다.
복잡한 표현식 (괄호가있는 표현)을 사용하면 Equal_Position ()가 괄호 안에있을 수 있습니다.
SELECT * FROM Namespace WHERE (f1 >= 5 AND f2 = 100 EQUAL_POSITION(f1,f2)) OR (f3 = 3 AND f4 < 4 AND f5 = 7 EQUAL_POSITION(f3,f4,f5));
SELECT * FROM Namespace WHERE (f1 >= 5 AND f2 = 100 AND f3 = 3 AND f4 < 4 EQUAL_POSITION(f1,f3) EQUAL_POSITION(f2,f4)) OR (f5 = 3 AND f6 < 4 AND f7 = 7 EQUAL_POSITION(f5,f7));
SELECT * FROM Namespace WHERE f1 >= 5 AND (f2 = 100 AND f3 = 3 AND f4 < 4 EQUAL_POSITION(f2,f3)) AND f5 = 3 AND f6 < 4 EQUAL_POSITION(f1,f5,f6); equal_position 다음 조건에서 작동하지 않습니다. NULL, 비어 있고 (빈 매개 변수 목록 포함).
네임 스페이스 잠금 장치에서 실행되는 원자 함수가 있으므로 데이터 일관성을 보장합니다.
이러한 기능은 3-Rd 및 다음 인수로 업스트/삽입/업데이트로 전달할 수 있습니다.
이러한 함수가 제공되면 참조로 전달 된 항목은 업데이트 된 값으로 변경됩니다.
// set ID field from serial generator
db . Insert ( "items" , & item , "id=serial()" )
// set current timestamp in nanoseconds to updated_at field
db . Update ( "items" , & item , "updated_at=now(NSEC)" )
// set current timestamp and ID
db . Upsert ( "items" , & item , "updated_at=now(NSEC)" , "id=serial()" )데이터 만료는 제한된 기간 동안 만 지속되어야하는 기계 생성 이벤트 데이터, 로그 및 세션 정보를 포함한 일부 클래스의 정보에 유용합니다.
Reindexer를 사용하면 네임 스페이스 항목에 대한 TTL (Time to Live)을 설정할 수 있습니다. 네임 스페이스에 ttlindex를 추가하면 지정된 초 후에 항목이 자동으로 제거됩니다.
TTL 인덱스는 INT64 필드에서만 작동하며 UNIX 타임 스탬프 데이터를 저장합니다. TTL 인덱스가 포함 된 항목은 expire_after 초 후에 만료됩니다. Golang에서 ttlindex를 선언하는 예 :
type NamespaceExample struct {
ID int `reindex:"id,,pk" json:"id"`
Date int64 `reindex:"date,ttl,,expire_after=3600" json:"date"`
}
...
ns . Date = time . Now (). Unix ()이 경우 네임 스페이스 네임 스페이스 면제 항목은 네임 스페이스 예를 들어 3600 초 안에 만료됩니다.
TTL 인덱스는 TTL이 아닌 인덱스와 같은 방식으로 쿼리를 지원합니다.
소스 데이터가 JSON 형식으로 사용할 수있는 경우 JSON을 Reindexer로 직접 전달하여 Upsert/Delete 작업의 성능을 향상시킬 수 있습니다. JSON Dessorialization은 GO 코드에서 추가 할당/사막화없이 C ++ 코드에 의해 수행됩니다.
Upsert 또는 Delete 함수는 JSON과 [] 바이트 인수를 전달하여 JSON을 처리 할 수 있습니다.
json := [] byte ( `{"id":1,"name":"test"}` )
db . Upsert ( "items" , json )더 빠른 것과 같습니다.
item := & Item {}
json . Unmarshal ([] byte ( `{"id":1,"name":"test"}` ), item )
db . Upsert ( "items" , item )JSON 형식의 쿼리 결과를 직렬화 해야하는 경우 Reindexer에서 JSON 형식의 결과를 직접 얻어 성능을 향상시킬 수 있습니다. JSON 직렬화는 GO 코드에서 추가 할당/직렬화없이 C ++ 코드로 수행됩니다.
...
iterator := db . Query ( "items" ).
Select ( "id" , "name" ). // Filter output JSON: Select only "id" and "name" fields of items, another fields will be omitted. This fields should be specified in the same case as the jsonpaths corresponding to them.
Limit ( 1 ).
ExecToJson ( "root_object" ) // Name of root object of output JSON
json , err := iterator . FetchAll ()
// Check the error
if err != nil {
panic ( err )
}
fmt . Printf ( "%s n " , string ( json ))
...이 코드는 다음과 같은 것을 인쇄합니다.
{ "root_object" : [{ "id" : 1 , "name" : " test " }] } 레이스 조건을 피하기 위해 기본적으로 객체 캐시가 꺼지고 모든 객체가 각 쿼리에 따라 Reindexer 내부 형식 ( CJSON )에서 할당되어 사형화됩니다. 사막화는 사용 반사이므로 속도는 최적이지 않습니다 (실제로 CJSON Desorialization은 JSON 보다 ~ 3-10 배, GOB 보다 ~ 1.2 배 더 빠릅니다). 성능은 여전히 반사 오버 헤드에 의해 심각하게 제한됩니다.
객체 캐시를 활성화하는 두 가지 방법이 있습니다.
Object가 DeepCopy 인터페이스를 구현하면 Reindexer는 객체 캐시를 켜고 DeepCopy 인터페이스를 사용하여 객체를 캐시에서 쿼리 결과로 복사합니다. DeepCopy 인터페이스는 소스 객체의 깊은 사본을 작성하는 것이 좋습니다.
다음은 DeepCopy 인터페이스 구현 샘플입니다
func ( item * Item ) DeepCopy () interface {} {
copyItem := & Item {
ID : item . ID ,
Name : item . Name ,
Articles : make ([] int , cap ( item . Articles ), len ( item . Articles )),
Year : item . Year ,
}
copy ( copyItem . Articles , item . Articles )
return copyItem
} 쿼리 속도를 높이고 각 쿼리 당 새 개체를 할당하지 않으려면 쿼리 반환 객체를 객체 캐시에서 직접 요청할 수 있습니다. 이 동작을 활성화하려면 Iterator 에서 AllowUnsafe(true) 호출하십시오.
경고 : 사용하면 AllowUnsafe(true) 쿼리가 공유 포인터를 객체 캐시의 스트러크에 반환합니다. 따라서 응용 프로그램은 반환 된 객체를 수정해서는 안됩니다.
res , err := db . Query ( "items" ). WhereInt ( "id" , reindexer . EQ , 1 ). Exec (). AllowUnsafe ( true ). FetchAll ()
if err != nil {
panic ( err )
}
if len ( res ) > 1 {
// item is SHARED pointer to struct in object cache
item = res [ 0 ].( * Item )
// It's OK - fmt.Printf will not modify item
fmt . Printf ( "%v" , item )
// It's WRONG - can race, and will corrupt data in object cache
item . Name = "new name"
} 기본적으로 객체 캐시의 최대 크기는 각 네임 스페이스에 대해 256000 항목입니다. 최대 크기를 변경하려면 ObjCacheSize NamespaceOptions 의 방법을 사용하여 OpenNamespace로 전달하십시오. 예를 들어
// Set object cache limit to 4096 items
db . OpenNamespace ( "items_with_huge_cache" , reindexer . DefaultNamespaceOptions (). ObjCacheSize ( 4096 ), Item {})!이 캐시는 다른 노드에서 복제 된 네임 스페이스에 사용해서는 안됩니다. 해당 복제의 네임 스페이스에는 일치하지 않을 수 있습니다.
지원되는 유일한 지오메트리 데이터 유형은 2D 포인트이며, Golang에서 [2]float64 ( reindexer.Point )로 구현되었습니다.
SQL에서는 ST_GeomFromText('point(1 -3)') 로 포인트를 만들 수 있습니다.
지오메트리 필드에 대한 유일한 지원 요청은 지점에서 멀리 떨어진 모든 지점을 찾는 것입니다. 아래 예를 들어 DWithin(field_name, point, distance) .
해당 SQL 기능은 ST_DWithin(field_name, point, distance) 입니다.
RTREE 인덱스는 포인트를 위해 생성 될 수 있습니다. 그렇게하려면 rtree 및 linear , quadratic , greene 또는 rstar 태그를 선언해야합니다. linear , quadratic , greene 또는 rstar RTREE 구조의 알고리즘이 사용되는 것을 의미합니다. 여기에서 알고리즘은 삽입을 위해 최적화에서 검색 최적화까지 순서대로 나열됩니다. 그러나 데이터에 따라 다릅니다. 당신에게 더 적합한 테스트. 기본 알고리즘은 rstar 입니다.
type Item struct {
id int `reindex:"id,,pk"`
pointIndexed reindexer. Point `reindex:"point_indexed,rtree,linear"`
pointNonIndexed reindexer. Point `json:"point_non_indexed"`
}
query1 := db . Query ( "items" ). DWithin ( "point_indexed" , reindexer. Point { - 1.0 , 1.0 }, 4.0 ) SELECT * FROM items WHERE ST_DWithin(point_non_indexed, ST_GeomFromText( ' point(1 -3.5) ' ), 5 . 0 ); 이 코드 스 니펫과 마찬가지로 db.SetLogger() 메소드에 의해 Reindexer Logger를 켤 수 있습니다.
type Logger struct {
}
func ( Logger ) Printf ( level int , format string , msg ... interface {}) {
log . Printf ( format , msg ... )
}
...
db . SetLogger ( Logger {}) Reindexer는 느린 동작의 로깅을 지원합니다. #config 시스템 네임 스페이스의 profiling.long_queries_logging 섹션을 통해 구성 할 수 있습니다. 다음 작업의 로깅을 구성 할 수 있습니다.
쿼리 선택 :
threshold_us (integer) : 선택 쿼리의 실행을위한 임계 값 (마이크로 초). 초과하면 threshold_us 가 -1 로깅이 비활성화 된 경우 코어 로그 항목이 이루어집니다.normalized (boolean) : 정규화 된 형태로 쿼리를 출력합니다.쿼리 업데이트 및 삭제 :
threshold_us (integer) : 업데이트 또는 삭제 쿼리 실행을위한 임계 값 (마이크로 초). 초과하면 threshold_us 가 -1 로깅이 비활성화 된 경우 코어 로그 항목이 이루어집니다.normalized (boolean) : 정규화 된 형태로 쿼리를 출력합니다.업무:
threshold_us (integer) : threshold_us 가 총 트랜잭션 커밋 시간으로 -1 로깅 인 경우 총 트랜잭션 커밋 시간의 임계 값 (마이크로 초).avg_step_threshold_us (integer) : 트랜잭션의 평균 단계 시간에 대한 임계 값 (마이크로 초). avg_step_threshold_us 평균 트랜잭션의 단계 기간에 따라 -1 로깅 인 경우 비활성화됩니다.또 다른 유용한 기능은 처리 된 쿼리의 디버그 인쇄입니다. 인쇄 쿼리 세부 사항을 디버그하려면 두 가지 방법이 있습니다.
db.SetDefaultQueryDebug(namespace string,level int) - 전 세계적으로 네임 스페이스 별 쿼리의 인쇄 세부 사항을 활성화합니다.
query.Debug(level int) - 쿼리 실행 level 의 인쇄 세부 정보는 수준의 수준입니다.
reindexer.INFO 쿼리 조건 만 인쇄합니다
reindexer.TRACE 타이밍으로 쿼리 조건 및 실행 세부 정보를 인쇄합니다.
query.Explain () - 쿼리 실행 세부 사항을 계산하고 저장합니다.
iterator.GetExplainResults () - 쿼리 실행 세부 정보를 반환합니다
Reindexer has support for TCMalloc (which is also a part of GPerfTools) and JEMalloc allocators (check ENABLE_TCMALLOC and ENABLE_JEMALLOC in CMakeLists.txt).
If you have built standalone server from sources available allocators will be detected and used automatically.
In go:generate builds and prebuilt packages reindexer has TCMalloc support, however none of TCMalloc libraries will be linked automatically. To force allocator's libraries linkage LD_PRELOAD with required library has to be used:
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc_and_profiler.so ./my_executable
Custom allocator may be handy to track memory consummation, profile heap/CPU or to improve general performance.
Because reindexer core is written in C++ all calls to reindexer and their memory consumption are not visible for go profiler. To profile reindexer core there are cgo profiler available. cgo profiler now is part of reindexer, but it can be used with any another cgo code.
Usage of cgo profiler is very similar with usage of go profiler.
import _ "github.com/restream/reindexer/v3/pprof" go func () {
log . Println ( http . ListenAndServe ( "localhost:6060" , nil ))
}()HEAPPROFILE=/tmp/pprofpprof -symbolize remote http://localhost:6060/debug/cgo/pprof/heapInternal Reindexer's profiler is based on gperf_tools library and unable to get CPU profile via Go runtime. However, go profiler may be used with symbolizer to retrieve C++ CPU usage.
import _ "net/http/pprof" go func () {
log . Println ( http . ListenAndServe ( "localhost:6060" , nil ))
}()REINDEXER_CGOBACKTRACE=1pprof -symbolize remote http://localhost:6060/debug/pprof/profile ? seconds=10Due to internal Golang's specific it's not recommended to try to get CPU and heap profiles simultaneously, because it may cause deadlock inside the profiler.
Go binding for Reindexer comes with optional support for OpenTelemetry integration.
To enable generation of OpenTelemetry tracing spans for all exported client side calls ( OpenNamespace , Upsert , etc), pass reindexer.WithOpenTelemetry() option when creating a Reindexer DB instance:
db := reindexer . NewReindex ( "cproto://user:[email protected]:6534/testdb" , reindexer . WithOpenTelemetry ()) All client side calls on the db instance will generate OpenTelemetry spans with the name of the performed operation and information about Reindexer DSN, namespace name (if applicable), etc.
For example, a call like this on the db instance above:
db . OpenNamespace ( "items" , reindexer . DefaultNamespaceOptions (), Item {}) will generate an OpenTelemetry span with the span name of Reindexer.OpenNamespace and with span attributes like this:
rx.dsn : cproto://user:[email protected]:6534/testdbrx.ns : items Use opentelemetry-go in your client go application to export the information externally. For example, as a minimum, you will need to configure OpenTelemetry SDK exporter to expose the generated spans externally (see the Getting Started guide for more information).
A list of connectors for work with Reindexer via other program languages (TBC later):
Pyreindexer is official connector, and maintained by Reindexer's team. It supports both builtin and standalone modes. Before installation reindexer-dev (version >= 2.10) should be installed. See installation instructions for details.
For install run:
pip3 install pyreindexerURLs:
Python version >=3.6 is required.
Reindexer for java is official connector, and maintained by Reindexer's team. It supports both builtin and standalone modes. For enable builtin mode support reindexer-dev (version >= 3.1.0) should be installed. See installation instructions for details.
For install reindexer to Java or Kotlin project add the following lines to maven project file
<dependency>
<groupId>com.github.restream</groupId>
<artifactId>rx-connector</artifactId>
<version>[LATEST_VERSION]</version>
</dependency>
URL: https://github.com/Restream/reindexer-java
Note: Java version >= 1.8 is required.
Spring wrapper for Java-connector: https://github.com/evgeniycheban/spring-data-reindexer
URL: https://github.com/Smolevich/reindexer-client
URL: https://github.com/coinrust/reindexer-rs
URL: https://github.com/oruchreis/ReindexerNet
Currently, Reindexer is stable and production ready, but it is still a work in progress, so there are some limitations and issues:
You can get help in several ways:
Landing: https://reindexer.io/
Packages repo: https://repo.reindexer.io/
More documentation (RU): https://reindexer.io/reindexer-docs/