
Reindexerは、ハイレベルのクエリビルダーインターフェイスを備えた埋め込み可能なインメモリのドキュメント指向データベースです。
Rewindexerの目標は、複雑なクエリで高速検索を提供することです。私たちはレプリームでElasticsearchに満足しておらず、よりパフォーマンスのある代替手段としてRewindexerを作成しました。
コアはC ++で記述されており、アプリケーションレベルAPIはGOになっています。
このドキュメントでは、GoコネクタとそのAPIについて説明します。 Reindexer ServerとHTTP APIに関する情報を取得するには、Reindexerドキュメントを参照してください
Reindexerの2つのLTSバージョンがあります:v3.xxとv4.xx
3.XXは現在、主流のブランチであり、4.XX(リリース/4ブランチ)は、実験的なラフトクラスターとシャーディングサポートを備えたベータバージョンです。ストレージはこれらのバージョン間で互換性がありますが、複製構成はまったく異なります。バージョン3と4では、すべての同じバグ修正と機能を取得しています(複製関連のバグフィックスを除く)。
主な機能:
パフォーマンスは最初から最優先事項であり、なんとかそれをかなり良いものにすることができたと思います。ベンチマークは、Rewendexerのパフォーマンスが典型的なキー価値データベースと同等であることを示しています。単一の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 ...ベンチマークレポのベンチマーク結果と詳細を参照してください
Rewindexerは、できるだけ少ないメモリを消費することを目指しています。ほとんどのクエリは、メモリの割り当てなしで処理されます。
それを達成するために、C ++とGOレベルの両方で、いくつかの最適化が採用されています。
ドキュメントとインデックスは、密なバイナリC ++構造体に保存されるため、Goのゴミコレクターに負荷を課すことはありません。
文字列の複製がマージされます。
メモリオーバーヘッドは、ドキュメントごとに約32バイト +検索インデックスごとに約4〜16バイトです。
クエリの実行後に作成された敏arialializedドキュメントのGOレベルにオブジェクトキャッシュがあります。将来のクエリは事前に想定されたドキュメントを使用します。
クエリインターフェイスは、 sync.Poolを使用して、内部構造とバッファーを再利用します。これらのテクノロジーの組み合わせにより、Reindexerは割り当てなしでほとんどのクエリを処理できます。
Reindexerには内部フルテキスト検索エンジンがあります。全文検索の使用文書と例はこちらです
Rewindexerは、LevelDBを介してDiskにドキュメントを保存し、ドキュメントをロードできます。ドキュメントは、バックグラウンドで自動的に大きなバッチによって非同期にストレージバックエンドに書き込まれます。
名前空間が作成されると、そのドキュメントはすべて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" )
...クエリビルダーインターフェイスが推奨されていることに注意してください。より多くの機能があり、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サブクエリは、場所の条件の一部でもあります。
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 Rewendexerは3つの異なるモードで実行できます。
embedded (builtin) Reindexerは、静的ライブラリとしてアプリケーションに埋め込まれており、個別のサーバープロセスを必要としません。embedded with server (builtinserver) Reindexerは、静的ライブラリとしてアプリケーションに埋め込まれ、サーバーを起動します。このモードでは、他のクライアントはCPROTO、UCProto、またはHTTPを介してアプリケーションに接続できます。standalone ReindexerはStandAloneサーバーとして実行され、アプリケーションはネットワークまたはUNIXドメインソケットを介してReindexerに接続します。このモードでは、Reindexerのゴーバインディングは、Reindexerの静的ライブラリに依存しません。
Reindexerサーバーを取得する最も簡単な方法は、DockerHubからDockerイメージを引くことと実行することです。
docker run -p9088:9088 -p6534:6534 -it reindexer/reindexerdockerfile
RewindexerのコアはC ++ 17で記述され、レベルDBをストレージバックエンドとして使用するため、Cmake、C ++ 17ツールチェーン、およびLevelDBをインストールする前にインストールする必要があります。
Reindexerを構築するには、G ++ 8+、Clang 7+、またはMingW64を構築する必要があります。
これらのモードでは、ReindexerのGo bindingは、Rewindexerの静的ライブラリ(コア、サーバー、リソース)に依存します。
この方法が推奨され、ほとんどのシナリオに適合します。
go.modを使用してGOモジュールは、モジュールのディレクトリにC ++ライブラリを構築することを許可していません。 Go Bindingは、PKG-Configを使用してライブラリのディレクトリを検出します。
Rewindexerのライブラリは、ソースから、またはPackage Managerを介して事前に作成されたパッケージからインストールする必要があります。
次に、モジュールを取得します。
go get -a github.com/restream/reindexer/v3変更されたRewendexerのソースが必要な場合は、そのような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この場合、ゴーバインディングは明示的なライブラリとパスのリストを生成し、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を使用すると、ベンダーディレクトリに配置されたbuiltin and builtinserver用のgo generate -mod=vendorを呼び出すことができます。
また、 git cloneを使用して、Reindexerのソースを単純にコピーすることも青少年プロジェクトにコピーすることも可能です。
これらの場合、Reindexerのgo.modからのすべての依存関係は、適切なバージョンで手動でインストールする必要があります。
内部的には、構造体は2つの部分に分割されます。
reindex structタグでマークされたインデックス化されたフィールドクエリは、インデックス化されたフィールドでのみ可能であり、 reindexタグでマークされています。 reindexタグには、インデックス名、タイプ、および追加オプションが含まれます。
reindex:"<name>[[,<type>],<opts>]"
name - インデックス名。type - インデックスタイプ:hash - EQで高速選択し、一致を設定します。デフォルトで使用されます。フィールドごとにゆっくりと非効率的なソートを可能にします。tree - 範囲ごと、GT、およびLTマッチを高速に選択します。 hashインデックスよりもEQとセットマッチの場合は少し遅くなります。フィールドごとに迅速な並べ替え結果が可能になります。text - 全文検索インデックス。フルテキスト検索の使用の詳細については、ここで説明します- - 列インデックス。フルスキャンテクニックで実装されているため、高速選択を実行できません。メモリが最小のオーバーヘッドがあります。ttl -TTLインデックス。これらのインデックスは、指定された秒後に期限切れになる日付フィールド(UNIXタイムスタンプとして保存)の表現に非常に便利です。rtreeドウェイチンの一致のみが利用可能です。 [2]float64 (またはreindexer.Point )フィールドタイプに対してのみ許容できます。詳細については、Geometryサブセクションを参照してください。opts - 追加のインデックスオプション:pk - フィールドは主キーの一部です。 structには、 pkでタグ付けされた少なくとも1つのフィールドが必要ですcomposite - 複合インデックスを作成します。フィールドタイプは空のstruct: struct{}でなければなりません。joined - フィールドは参加の受信者です。フィールドタイプは[]*SubitemTypeでなければなりません。dense - インデックスサイズを削減します。 hashとtreeの場合、一意のキー値ごとに8バイトを節約できます。 for- -要素ごとに4〜8バイトを節約します。選択性が高いインデックスには役立ちますが、選択性が低いtreeおよびhashインデックスには、更新パフォーマンスを大幅に減らすことができます。また、CPUキャッシュの最適化が不足しているため、 -で幅広いフルスキャンクエリがdenseが低下します。sparse -row(document)には、意図的に設定されている場合にのみ、スパースインデックスの値が含まれています。このタイプのインデックスの空の(またはデフォルト)レコードは行にありません(ドキュメント)。 RAMを節約できますが、パフォーマンスにコストがかかります。通常のインデックスよりも少し遅くなります。collate_numeric数値シーケンスで値順序を提供する文字列インデックスを作成します。フィールドタイプは文字列でなければなりません。collate_ascii ASCIIで動作するケース非感受性の文字列インデックスを作成します。フィールドタイプは文字列でなければなりません。collate_utf8 -case -ofsensensitive文字列インデックスの作成UTF8で動作します。フィールドタイプは文字列でなければなりません。collate_custom=<ORDER> - カスタムオーダー文字列インデックスを作成します。フィールドタイプは文字列でなければなりません。 <ORDER>は、ソート順序を定義する文字のシーケンスです。linear 、 quadratic 、 greene 、またはrstar rtreeインデックスの構築のためのアルゴリズムを指定します(デフォルトではrstar )。詳細については、Geometryサブセクションを参照してください。uuidこの値をuuidとして保存します。これは、文字列よりもUUIDSのRAM/ネットワーク消費の観点からははるかに効果的です。 UUIDに対しては、 hashおよび-インデックスタイプのみがサポートされています。バリアント0を除き、任意のUUIDバリアントで使用できます通常のインデックスを備えたフィールドは無視できません。条件is NULL sparseとarrayインデックスによってのみサポートされます。
デフォルトでは、Reindexerはすべてのネストされた構造体をスキャンし、名前空間(および指定されたインデックス)にフィールドを追加します。インデックス中にプライベート(エクスペリされたフィールド)をスキャンし、 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")
}Rewindexerは、フィールド(接合された名前空間のネストされたフィールドとフィールドを含む)または昇順または降順の式でドキュメントを並べ替えることができます。
非インデックスフィールドで並べ替えるには、すべての値を互いに変換する必要があります。つまり、同じタイプを持っているか、数値タイプのいずれかになります( bool 、 int 、 int64またはfloat )。
並べ替え式には以下を含めることができます
bool 、 int 、 int64 、 floatまたはstringタイプのフィールドおよびインデックス名(結合した名前空間のネストされたフィールドとフィールドを含む)。すべての値は、リーディングスペースと仕上げスペースを無視する数字に変換可能でなければなりません。rank() 、 abs() 、 ST_Distance() ;+ 、 - (unary and binary)、 * and / 。フィールド名の後に+が続く場合は、複合インデックス名を区別するためにスペースで分離する必要があります。参加した名前空間のフィールドは、次のようにjoined_namespace.fieldれている必要があります。
Abs()引数の絶対値を意味します。
Rank()一致のフルテキストランクを意味し、フルテキストクエリでのみ適用できます。
ST_Distance()は、ジオメトリポイント間の距離を意味します(Geometryサブセクションを参照)。ポイントは、現在の列または結合された名前空間または形式の固定点ST_GeomFromText('point(1 -3)')である可能性があります
sql queryでは、ソート式を引用する必要があります。
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使用できます。パターンに一致する文字列を探します。パターンでは、 _を意味し、 % charのシーケンスを意味します。
例:
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そしてそれをnullに設定します
UPDATE NS SET field = NULL WHERE id > 100インデックスされていないフィールドの場合、その値を異なるタイプの値に設定すると、完全に置き換えられます。インデックス化されたフィールドの場合、隣接するタイプ(積分型とブール)、数値文字列(「123456」など)から積分型および背面に変換することのみが可能です。 NULLにインデックス化されたフィールドを設定して、デフォルト値にリセットします。
既存のアイテムに新しいフィールドを追加することは可能です
UPDATE NS SET newField = ' Brand new! ' WHERE id > 100そして、このような複雑なネストされたパスによって新しいフィールドを追加することもできます
UPDATE NS SET nested . nested2 . nested3 . nested4 .newField = ' new nested field! ' WHERE id > 100Nested、Nested2、Nested3、Nested4、NewFieldはNested4のメンバーとしてNested、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 ()Rewendexerの更新メカニズムにより、配列フィールドを変更できます。既存の配列の特定のアイテムを変更するか、フィールド全体を置き換えることさえできます。
アイテムを更新するには、サブスクリプションオペレーターの構文を使用します。
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の終わりに要素を追加し、2番目のものはその前面に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のリストされた値のすべての発生を削除し、2番目の値は最初の発生のみを削除します。このコードをgolang SetExpression()で機能させるにはSet()の代わりに使用する必要があります。 1つの値を削除する必要がある場合は、正方形の括弧[5]または単純な値5使用できます。
UPDATE NS SET integer_array = array_remove(integer_array, [ 5 ]) update ns set integer_array = array_remove(integer_array, 5 )コマンドを削除することは、配列concatenateと組み合わせることができます。
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 ()最初のフィールドの値から2番目のフィールドの値を削除することができます。また、新しい値などを追加します。注:コマンドの最初のパラメーターは配列/フィールドアレイになると予想されます。2番目のパラメーターは、配列/Scalar/Field-Array/Field-Scalarです。値の互換性/変換性の場合
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 ()Rewendexerはトランザクションをサポートします。トランザクションはAtomic NameSpace Updateを実行します。同期および非同期トランザクションが利用可能です。トランザクションメソッドを開始するには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の2番目の引数は完了関数であり、サーバーの応答を受信した後に呼び出されます。また、準備プロセス中にエラーが発生した場合、 tx.Commitエラーを返す必要があります。したがって、 tx.Commitによって返されたエラーを確認するだけで十分です - 確かに、すべてのデータが正常にコミットされたかどうか。
トランザクションの変更量によっては、2つの可能なコミット戦略があります。
コミット戦略を選択するためのデータの量は、名前空間構成で選択できます。 struct DBNamespacesConfig (describer.go)のフィールドStartCopyPolicyTxSize 、 CopyPolicyMultiplier 、 TxSizeToAlwaysCopyを確認する
トランザクションサイズが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 ()この例では、Rewindexerはフードの下で反射を使用して、俳優のスライスを作成して俳優構造をコピーします。
接続クエリには、接続されている条件Andデフォルトで)、 Orオペレーターに接続Notれている条件On 1つから複数のものがあります。
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 、両方の名前空間の結合フィールドに一致する2つの名前空間からのデータを組み合わせます。 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 ( WhereIntの例から)では、両方のInnerJoin条件が評価されます。 Limit(0) InnerJoin (上記の例からのquery3 )の一部としてデータはデータに参加しません - 条件を検証するためだけにフィルターのように機能します。
RewindexerはSQL構造ANTI JOINてサポートしていませんが、結合で論理的な操作をサポートしています。実際、 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 and CountCached集約は許可されています。サブクエリは、複数の集約を同時に含めることはできません。
サブクエリは、同じ名前のスペースまたは別の名前に適用できます。
サブクエリは、別のサブクエリを含めることはできません。
アイテムの少なくとも1つがサブクエリに満足しているかどうかを確認する場合は、 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インデックスをstructに追加します。 Composite Indexは、複数のフィールドを含むインデックスであり、複数の個別のインデックスの代わりに使用できます。
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 }) Composite Indexにクエリを作成するには、[]インターフェイス{}を.WhereComposite関数に渡します。
// Get results where rating == 5 and year == 2010
query := db . Query ( "items" ). WhereComposite ( "rating+year" , reindexer . EQ ,[] interface {}{ 5 , 2010 })通常の(非fulltext)コンポジットインデックスのすべてのフィールドをインデックス作成する必要があります。つまり、Composite Index 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 - クエリの条件を満たすドキュメントの総数を取得するCountCachedクエリの条件を満たすドキュメントの総数を取得します。結果値はキャッシュされ、カウントキャッチされた集約を伴う他のクエリによって再利用される場合がありますAggregateMax最大フィールド値を取得しますAggregateMin最小フィールド値を取得しますAggregateSum - 合計フィールド値を取得しますAggregateAvg平均フィールド値を取得しますAggregateFacetフィールドファセット値を取得しますDistinct - フィールドの一意の値のリストを取得する集合体をサポートするために、 QueryにはメソッドAggregateAvg 、 AggregateSum 、 AggregateMin 、 AggregateMax 、 AggregateFacet 、およびDistinctものがQuery実行の前に呼び出される必要があります。集約ファセットは複数のデータ列に適用でき、その結果は任意のデータ列または「カウント」でソートされ、オフセットと制限によって切り取られます。この機能メソッドをサポートするために、 AggregateFacet 、メソッドのSort 、 Limit 、およびOffset備えたAggregationFacetRequestを返します。
マージ付きのクエリは、メインクエリから集約されたすべてのサブQuerieに集約を適用します。サブクエリは独自の集計を持つことはできません。 Merge-Queriesで利用可能な集約は、カウント、カウント、サム、ミン、マックスです。
集約結果を取得するために、 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 itemsReindexerでは、一致する値が同じインデックス位置にあるときに、配列フィールドでデータを検索できます。たとえば、構造の配列があります。
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 ) Array Elem[]のすべてのアイテムを見つけます。ここで、 f1は1に等しく、 f2 2に等しくなります。
EqualPosition関数により、等しいインデックスを持つ配列フィールドで検索できます。このようなクエリ:
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が100に等しいequal配列インデックスを持つ配列Elem[]のすべてのアイテムが見つかります(たとえば、クエリは両方の配列の3番目の要素のみが適切な値を持つ5つのアイテムを返します)。
複雑な式(括弧付きの式)を使用すると、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次の条件では機能しません:is null、empty、in in(空のパラメーターリストを使用)。
名前空間ロックの下で実行される原子機能があり、したがってデータの一貫性を保証します。
これらの関数は、3-RDおよび次の引数でUPSERT/INSERT/UPDATEに渡すことができます。
これらの機能が提供されると、参照項目で渡されたものが更新された値に変更されます
// 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()" )データの有効期限は、限られた期間のみ持続する必要があるマシンで生成されたイベントデータ、ログ、およびセッション情報など、一部のクラスの情報に役立ちます。
Rewindexerは、名前空間アイテムのTTL(Live to Live)を設定することを可能にします。 TTLINDEXをNAMESPACEに追加すると、指定された秒数の後にアイテムが自動的に削除されます。
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 ()この場合、名前空間名の項目namespaceexampleは、namespaceexample.dateフィールド値(UNIXタイムスタンプ)の3600秒後に期限切れになります。
TTLインデックスは、非TTLインデックスが行うのと同じようにクエリをサポートします。
ソースデータがJSON形式で利用可能である場合、JSONを直接渡すことにより、UPSERT/削除操作のパフォーマンスを改善することができます。 JSONの脱代化は、GOコードに追加のアロック/脱介入なしで、C ++コードによって行われます。
upsertまたは削除関数は、[] 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降下はJSONよりも3〜10倍高速で、 GOBよりも1.2倍高速です)が、反射オーバーヘッドによってパフォーマンスは依然として深刻に制限されています。
オブジェクトキャッシュを有効にする方法は2つあります。
オブジェクトがDeepCopyインターフェイスを実装している場合、Reindexerはオブジェクトキャッシュをオンにし、DeepCopyインターフェイスを使用してオブジェクトをキャッシュからクエリ結果にコピーします。 DeepCopyインターフェイスは、ソースオブジェクトのディープコピーを作成する責任があります。
DeepCopy Interfaceの実装のサンプルを次に示します
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 );Reindexer Loggerは、このコードのスニペットのように、 db.SetLogger()メソッドによってオンになります。
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ログが無効になっています。もう1つの便利な機能は、処理されたクエリのデバッグプリントです。印刷クエリの詳細をデバッグするには、2つの方法があります。
db.SetDefaultQueryDebug(namespace string,level int) -Namespaceによるすべてのクエリの詳細をグローバルに有効にする
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/