
ReIndexer是具有高級查詢構建器接口的可嵌入,內存,面向文檔的數據庫。
Reindexer的目標是提供複雜的查詢快速搜索。我們在Drestam上對Elasticsearch不滿意,並創建了ReIndexer作為更具性能的替代方案。
核心用C ++編寫,應用級別API在GO中。
該文檔描述了GO連接器及其API。要獲取有關ReIndexer Server和HTTP API的信息,請參閱ReIndexer文檔
有兩個LTS-REINDEXER可用:v3.xx和v4.xx
3.xx當前是我們的主流分支,4.xx(釋放/4個分支)是Beta-version,具有實驗Raft-Cluster和Sharding Support。這些版本之間的存儲是兼容的,但是,複製配置是完全不同的。版本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 ...請參閱基準測試結果和更多細節。
Reindexer的目標是消耗盡可能少的內存;大多數查詢都是根本沒有任何內存分配的處理。
為此,在C ++和GO級別上都採用了幾種優化:
文檔和索引存儲在密集的二進制C ++結構中,因此它們不會對Go的垃圾收集器施加任何負載。
字符串副本合併。
每個文檔 +≈4-16字節每個搜索索引的內存開銷約為32個字節。
在查詢執行後產生的值得序列化文檔的GO級別上有一個對象緩存。未來的查詢使用預序列化的文檔,該文檔削減了重複的避難和分配成本
查詢接口使用sync.Pool重複使用內部結構和緩衝區。這些技術的組合使Reindexer可以無需分配而處理大多數查詢。
Reindexer具有內部全文搜索引擎。全文搜索用法文檔和示例在這裡
ReIndexer可以將文檔存儲到disk via 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 ++的基本示例,然後去此處
作為查詢構建器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 '如果字段名稱不以alpha開頭,則“ _”或“#”必須以雙引號(示例:
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 Reindexer可以以3種不同的模式運行:
embedded (builtin) Reindexer嵌入為靜態庫中,並且不需要單獨的服務器進程。embedded with server (builtinserver) ReIndexer的嵌入式嵌入到應用程序中,作為靜態庫,然後啟動服務器。在此模式下,其他客戶端可以通過CPROTO,UCPROTO或HTTP連接到應用程序。standalone ReIndexer作為獨立服務器運行,應用程序通過網絡或UNIX域插座連接到ReIndexer。在此模式下,ReIndexer的Go Binding不取決於Reindexer的靜態庫。
獲取ReIndexer Server的最簡單方法是從Dockerhub撤回並運行Docker Image。
docker run -p9088:9088 -p6534:6534 -it reindexer/reindexerDockerfile
ReIndexer的Core用C ++ 17編寫,並將LevelDB用作存儲後端,因此CMAKE,C ++ 17工具鍊和LevelDB必須在安裝ReIndexer之前安裝。
要構建ReIndexer,需要G ++ 8+,Clang 7+或Mingw64。
在這些模式下,ReIndexer的Go綁定取決於ReIndexer的靜態庫(Core,Server和Resource)。
這種方式建議使用,並且適合大多數情況。
使用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在這種情況下,Go Binding將生成顯式庫和路徑列表,並且不會使用PKG-Config。
如果您不使用go.mod,則可以通過這種方式從來源獲取和構建ReIndexer:
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的源複製到供應商-Directory中。
使用vend您將可以致電go generate -mod=vendor builtin和builtinserver的供應商,並放置在供應商目錄中。
也可以使用git clone將Reindexer的來源複製到青年項目中。
在這些情況下,所有依賴性的依賴項必須用適當的版本手動安裝mod。
在內部,結構分為兩個部分:
reindex struct標籤僅在索引字段上進行查詢,並標有reindex標籤。 reindex標籤包含索引名稱,類型和其他選項:
reindex:"<name>[[,<type>],<opts>]"
name - 索引名稱。type - 索引類型:hash - 快速選擇EQ和SET匹配。默認情況下使用。允許按字段進行緩慢效率低下的排序。tree - 快速按範圍,GT和LT匹配。 EQ和設定匹配hash索引要慢一些。允許按字段進行快速分類結果。text - 全文搜索索引。全文搜索的用法詳細信息在這裡描述- - 列索引。無法執行快速選擇,因為它是通過全掃描技術實現的。頭頂上有最小的內存。ttl -TTL索引僅適用於INT64字段。這些索引非常方便地表示日期字段(存儲為UNIX時間戳),該索引在指定的秒數後到期。rtree僅可用Dwithin匹配。僅適用於[2]float64 (或reindexer.Point )字段類型。有關詳細信息,請參見幾何小節。opts - 其他索引選項:pk - 字段是主要鍵的一部分。 struct必須至少有1個字段用pk標記composite - 創建複合索引。字段類型必須是一個空結構: struct{} 。joined - 字段是加入的接收者。字段類型必須為[]*SubitemType 。dense - 降低索引尺寸。對於hash和tree它將每個唯一的鑰匙值節省8個字節。對於-每個元素將節省4-8個字節。對於具有較高選擇性的索引很有用,但是對於具有低選擇性的tree和hash索引可以嚴重降低更新性能。同樣,由於缺乏CPU緩存優化,密集dense -會減慢寬度的全面查詢。sparse - 行(文檔)僅在故意設置的情況下包含稀疏索引的值 - 該行中沒有此類索引的空(或默認)記錄(文檔)。它允許節省RAM,但它會使您的性能付出代價 - 它的工作原理比常規索引慢一點。collate_numeric創建字符串索引,以數字序列提供值順序。字段類型必須是字符串。collate_ascii創建對案例不敏感的字符串索引與ASCII一起使用。字段類型必須是字符串。collate_utf8創建對案例不敏感的字符串索引與UTF8一起使用。字段類型必須是字符串。collate_custom=<ORDER> - 創建自定義訂單字符串索引。字段類型必須是字符串。 <ORDER>是字母的順序,它定義了排序順序。linear , quadratic , greene或rstar指定用於構建rtree索引的算法(默認情況下為rstar )。有關詳細信息,請參見幾何小節。uuid將此值存儲為UUID。從RAM/網絡完成UUID的角度來看,這比字符串更有效。僅支持hash和-索引類型。可以與任何UUID變體一起使用,除了變體0帶有常規索引的字段不可謀殺。條件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")
}Reindexer可以按字段(包括連接名稱空間的嵌套和字段)或按升序或降序順序進行表達式對文檔進行排序。
要按非指數字段進行排序,所有值必須相互轉換,即具有相同類型,或者是數字類型之一( bool ,int, int , int64或float )。
排序表達式可以包含:
bool , int , int64 , float或string類型。所有值都必須轉換為忽略領先空間和飾面空間的數字;rank() , abs()和ST_Distance() ;+ , - (一元和二進制), *和/ 。如果字段名稱後面+必須通過空間分開以區分複合索引名稱。必須像這樣編寫連接的名稱空間的字段: joined_namespace.field 。
Abs()表示論點的絕對價值。
Rank()表示匹配的全文等級,並且僅適用於全文查詢。
ST_Distance()表示幾何點之間的距離(請參見幾何小節)。這些點可以是當前或連接的命名空間中的列或格式的固定點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可以使用。它尋找與圖案相匹配的字符串。在模式中_表示任何字符, %表示任何字符序列。
去示例:
query := db . Query ( "items" ).
Where ( "field" , reindexer . LIKE , "pattern" )SQL示例:
SELECT * FROM items WHERE fields LIKE ' pattern ''me_t'對應於“遇見”,“肉”,“融化”等等,等等“%tion”對應於'tion','tion',``條件'',''''
注意:類似使用掃描方法的條件。它可用於調試目的,也可以在其他良好選擇條件下查詢。
通常,對於以合理的速度,我們建議使用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 > 100將創建以下嵌套對象:嵌套,Nested2,Nested3,Nested4和Newfield作為對象Nested4的成員。
在Golang代碼中使用更新查詢的示例:
db . Query ( "items" ). Where ( "id" , reindexer . EQ , 40 ). Set ( "field1" , values ). Update ()ReIndexer可以更新和添加對象字段。可以通過struct,ap或字節數組(即對象表示的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只能用字符串作為鍵使用。 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機制可以修改數組字段:修改現有數組的某些項目,甚至更換整個字段。
更新項目訂閱操作員語法:
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 ()可以從第一個字段的值中刪除第二個字段的值。還要添加新值等。注意:命令中的第一個參數預計是數組/field-array,第二個參數可以是數組/標量/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 ()Reindexer支持交易。交易是執行原子名稱空間更新。有同步和異步交易可用。啟動事務方法db.BeginTx()使用。此方法創建事務對象,該對象為應用程序提供了常規更新/UPSERT/INSERT/DELETE接口。對於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 )
}為了加快批量記錄的插入,可以使用async模式。
// 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返回的錯誤是足夠的 - 確保所有數據均已成功合作。
根據交易的變化數量,有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 ()在此示例中,ReIndexer使用引擎蓋下的反射來創建Actor Slice和Copy Actor Struct。
加入查詢可能在與之相關的條件And (默認情況下) Or Not操作員的條件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條件下實現短路:如果上一個條件為True,則未評估下一個條件。但是在InnerJoin的情況下,它的工作方式有所不同:在query1中(從上面的示例)中,儘管有WhereInt的結果,但都評估了兩種InnerJoin條件。 Limit(0)作為InnerJoin的一部分(從上面的示例中query3 )不連接任何數據 - 它像過濾器一樣工作以驗證條件。
Reindexer不支持ANTI JOIN SQL構建,但是,它支持與Joins的邏輯操作。實際上, 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聚合。子查詢不能同時包含多個聚合。
子查詢可以應用於同一名稱空間或另一個名稱空間。
子查詢不能包含另一個子查詢,加入或合併。
如果要檢查至少一個項目是否滿足子征服,則可以使用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 )文檔可以將多個字段作為主要鍵。要啟用此功能,將復合索引添加到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 })為了對複合索引進行查詢,請將[]接口{}傳遞到查詢構建器的.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 - 獲取符合查詢條件的文檔總數CountCached - 獲取符合查詢條件的文檔總數。結果值將被緩存,並且可以通過Countcachectregation的其他查詢重複使用AggregateMax獲取最大字段值AggregateMin - 獲取最小現場值AggregateSum - 獲取總和字段值AggregateAvg - 獲取平均現場值AggregateFacet - 獲取字段facet值Distinct - 獲取該字段唯一值的列表為了支持聚合, Query具有AggregateAvg方法, AggregateSum , AggregateMin , AggregateMax , AggregateFacet和Distinct這些方法應在Query執行之前調用:這將要求ReIndexer計算數據聚合。聚合方面適用於多個數據列,其結果可以通過任何數據列或“計數”來對其進行排序,並通過偏移和限制切斷。為了支持此功能方法, AggregateFacet返回具有方法Sort , Limit和Offset AggregationFacetRequest 。
與合併合併的查詢將對所有合併的子查詢應用於總查詢的匯總。亞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 items當匹配值具有相同的索引位置時,ReIndexer允許在數組字段中搜索數據。例如,我們有一系列結構:
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 )找到所有陣列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);將找到具有equal數組索引的數組Elem[]的所有項目,其中f1大或等於5和f2等於100(例如,查詢返回的5個項目,其中兩個數組的第3個元素具有適當的值)。
具有復雜表達式(帶有括號的表達式)等於_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和下一個參數中的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()" )數據到期對於某些類別的信息很有用,包括機器生成的事件數據,日誌和會話信息,這些信息只需要在有限的時間內持續存在。
ReIndexer使得可以為命名空間項目設置TTL(Live)。在指定的秒數之後,將TTLINDEX添加到名稱空間會自動刪除項目。
TTL索引僅適用於INT64字段,並存儲UNIX TIMESTAMP數據。 expire_after秒鐘後Expire__Expire__Expire_Exex的項目。 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 ()在這種情況下,命名空間命名空間exexample的項目在namespaceexample之後的3600秒內到期。
TTL索引以非TTL索引的方式支持查詢。
如果以JSON格式獲得源數據,則可以通過將JSON直接傳遞給ReIndexer來提高UPSERT/DELETE操作的性能。 JSON避難所將通過C ++代碼完成,而GO代碼中沒有額外的分配/避難所化。
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序列化將通過C ++代碼完成,而無需在GO代碼中進行額外的分配/序列化。
...
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的速度比GOB快〜1.2倍),但性能仍然受到反射開銷的嚴重限制。
有兩種啟用對象緩存的方法:
如果對像是實現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個項目。要更改最大尺寸,請使用傳遞給OpenNamespace的NamespaceOptions ObjCacheSize方法的方法。例如
// 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支持記錄緩慢的動作。它可以通過profiling.long_queries_logging #config系統名稱空間進行配置。可以配置下一個操作的記錄:
選擇查詢:
threshold_us (integer) :用於執行選擇查詢的閾值值(以微秒為單位)。如果超過超過,則將進行核心gog條目,如果禁用了threshold_us為-1記錄。normalized (boolean) :以歸一化形式輸出查詢。更新和刪除查詢:
threshold_us (integer) :執行更新或刪除查詢的閾值值(以微秒為單位)。如果超過超過,則將進行核心gog條目,如果禁用了threshold_us為-1記錄。normalized (boolean) :以歸一化形式輸出查詢。交易:
threshold_us (integer) :閾值值(以微秒為單位),如果threshold_us為-1通過總交所提交時間來記錄,則禁用了threshold_us。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支持TCMalloc(也是Gperftools的一部分)和Jemalloc分配器(在cmakelists.txt中檢查ENABLE_TCMALLOC和ENABLE_JEMALLOC )。
如果您已經從可用的分配器中構建了獨立的服務器,則將自動檢測並自動使用。
在go:generate構建和預構建的軟件包Reindexer具有TCMALLOC支持,但是TCMalloc庫都不會自動鏈接。必須使用分配器的庫鏈接LD_PRELOAD與所需庫:必須使用:
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libtcmalloc_and_profiler.so ./my_executable
自定義分配器可能方便跟踪內存完整,配置文件堆/CPU或提高一般性能。
因為Reindexer Core用C ++編寫了所有對ReIndexer的調用,並且Go Profiler不可見它們的內存消耗。要配置Reindexer Core,有CGO Profiler可用。 CGO Profiler現在是ReIndexer的一部分,但可以與任何其他CGO代碼一起使用。
使用CGO剖面的使用與GO Profiler的使用非常相似。
import _ "github.com/restream/reindexer/v3/pprof" go func () {
log . Println ( http . ListenAndServe ( "localhost:6060" , nil ))
}()HEAPPROFILE=/tmp/pprof運行應用程序pprof -symbolize remote http://localhost:6060/debug/cgo/pprof/heapInternal Reindexer的Profiler基於GPERF_Tools庫,無法通過GO運行時獲得CPU配置文件。但是,GO Profiler可以與符號器一起使用以檢索C ++ CPU使用情況。
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=10由於內部Golang的具體特異性,不建議同時嘗試獲得CPU和堆積,因為這可能會在Profiler內部造成僵局。
依indexer的綁定帶有可選的OpenTelemetry集成的支持。
要為所有導出的客戶端呼叫( OpenNamespace , Upsert等)生成OpenTElemetry跟踪跨度跨度,請通過reindexer.WithOpenTelemetry()選項:
db := reindexer . NewReindex ( "cproto://user:[email protected]:6534/testdb" , reindexer . WithOpenTelemetry ()) db實例上的所有客戶端調用都將生成opentelemetry跨度,並具有執行操作的名稱以及有關ReIndexer DSN,名稱空間名稱(如果適用),等等的信息。
例如,在上面的db實例上這樣的調用:
db . OpenNamespace ( "items" , reindexer . DefaultNamespaceOptions (), Item {})將使用Reindexer.OpenNamespace的跨度名稱以及具有這樣的跨度屬性生成opentelemetry跨度:
rx.dsn : cproto://user:[email protected]:6534/testdbrx.ns : items在客戶端應用程序中使用OpenTelemetry-GO在外部導出信息。例如,至少,您需要配置OpenTelemetry SDK出口商以外部暴露生成的跨度(有關更多信息,請參見Getting Started指南”)。
通過其他程序語言(以後TBC)與Reindexer一起工作的連接器列表:
Pyreindexer是官方連接器,由Reindexer的團隊維護。它支持內置和獨立模式。在安裝ReIndexer-Dev(版本> = 2.10)之前,應安裝。有關詳細信息,請參見安裝說明。
用於安裝運行:
pip3 install pyreindexerURL:
需要Python版本> = 3.6。
Java的Reindexer是官方連接器,由Reindexer的團隊維護。它支持內置和獨立模式。為了啟用內置模式支持Reindexer-Dev(版本> = 3.1.0)。有關詳細信息,請參見安裝說明。
要安裝Reindexer到Java或Kotlin項目,將以下行添加到Maven Project文件
<dependency>
<groupId>com.github.restream</groupId>
<artifactId>rx-connector</artifactId>
<version>[LATEST_VERSION]</version>
</dependency>
URL:https://github.com/restream/reindexer-java
注意:Java版本> = 1.8。
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
目前,ReIndexer穩定且生產準備就緒,但仍在進行中,因此存在一些局限性和問題:
您可以通過幾種方式獲得幫助:
著陸:https://reindexer.io/
包裝庫:https://repo.reindexer.io/
更多文檔(RU):https://reindexer.io/reindexer-docs/