fix
This commit is contained in:
parent
fd28639f17
commit
eff399c4e4
355
alg/bplus.go
355
alg/bplus.go
|
@ -1,355 +0,0 @@
|
||||||
package alg
|
|
||||||
|
|
||||||
import "strings"
|
|
||||||
|
|
||||||
type IndexKey interface {
|
|
||||||
Compare(other IndexKey) int
|
|
||||||
}
|
|
||||||
|
|
||||||
type SortOrder struct {
|
|
||||||
Field string
|
|
||||||
Desc bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type IndexEntry struct {
|
|
||||||
Key IndexKey
|
|
||||||
Value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
const BTreeMinDegree = 2
|
|
||||||
|
|
||||||
type BTreeNode struct {
|
|
||||||
Keys []IndexKey
|
|
||||||
Values []interface{} // 叶子节点存储数据
|
|
||||||
Childs []*BTreeNode // 非叶子节点存储子节点
|
|
||||||
IsLeaf bool
|
|
||||||
Next *BTreeNode // 叶子节点之间的链表指针
|
|
||||||
Prev *BTreeNode
|
|
||||||
}
|
|
||||||
|
|
||||||
type BTree struct {
|
|
||||||
Root *BTreeNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBTreeNode(leaf bool) *BTreeNode {
|
|
||||||
return &BTreeNode{
|
|
||||||
Keys: make([]IndexKey, 0),
|
|
||||||
Values: make([]interface{}, 0),
|
|
||||||
Childs: make([]*BTreeNode, 0),
|
|
||||||
IsLeaf: leaf,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewBTree() *BTree {
|
|
||||||
return &BTree{
|
|
||||||
Root: NewBTreeNode(true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *BTree) Insert(key IndexKey, value interface{}) {
|
|
||||||
root := bt.Root
|
|
||||||
// 如果根节点已满,需要分裂
|
|
||||||
if len(root.Keys) == 2*BTreeMinDegree-1 {
|
|
||||||
newRoot := NewBTreeNode(false)
|
|
||||||
newRoot.Childs = append(newRoot.Childs, root)
|
|
||||||
splitChild(newRoot, 0)
|
|
||||||
bt.Root = newRoot
|
|
||||||
}
|
|
||||||
insertNonFull(bt.Root, key, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分裂子节点
|
|
||||||
func splitChild(parent *BTreeNode, index int) {
|
|
||||||
minDegree := BTreeMinDegree
|
|
||||||
fullNode := parent.Childs[index]
|
|
||||||
// 创建新节点
|
|
||||||
newNode := NewBTreeNode(fullNode.IsLeaf)
|
|
||||||
// 中间键位置
|
|
||||||
mid := minDegree - 1
|
|
||||||
|
|
||||||
// 拆分键和值
|
|
||||||
newNode.Keys = fullNode.Keys[mid:]
|
|
||||||
fullNode.Keys = fullNode.Keys[:mid]
|
|
||||||
|
|
||||||
if !fullNode.IsLeaf {
|
|
||||||
newNode.Childs = fullNode.Childs[mid:]
|
|
||||||
fullNode.Childs = fullNode.Childs[:mid]
|
|
||||||
} else {
|
|
||||||
// 叶子节点需要维护链表
|
|
||||||
newNode.Values = fullNode.Values[mid:]
|
|
||||||
fullNode.Values = fullNode.Values[:mid]
|
|
||||||
newNode.Next = fullNode.Next
|
|
||||||
newNode.Prev = fullNode
|
|
||||||
if fullNode.Next != nil {
|
|
||||||
fullNode.Next.Prev = newNode
|
|
||||||
}
|
|
||||||
fullNode.Next = newNode
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将中间键提升到父节点
|
|
||||||
parent.Keys = append(parent.Keys[:index+1], append([]IndexKey{fullNode.Keys[mid]}, parent.Keys[index+1:]...)...)
|
|
||||||
fullNode.Keys = fullNode.Keys[:mid]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插入非满节点
|
|
||||||
func insertNonFull(node *BTreeNode, key IndexKey, value interface{}) {
|
|
||||||
i := len(node.Keys) - 1
|
|
||||||
|
|
||||||
if node.IsLeaf {
|
|
||||||
// 在叶子节点插入
|
|
||||||
for i >= 0 && key.Compare(node.Keys[i]) < 0 {
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
// 插入键值
|
|
||||||
if i >= 0 {
|
|
||||||
node.Keys = append(node.Keys[:i+1], append([]IndexKey{key}, node.Keys[i+1:]...)...)
|
|
||||||
node.Values = append(node.Values[:i+1], append([]interface{}{value}, node.Values[i+1:]...)...)
|
|
||||||
} else {
|
|
||||||
node.Keys = append([]IndexKey{key}, node.Keys...)
|
|
||||||
node.Values = append([]interface{}{value}, node.Values...)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 找到子节点
|
|
||||||
for i >= 0 && key.Compare(node.Keys[i]) < 0 {
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
|
|
||||||
// 如果子节点已满,需要分裂
|
|
||||||
child := node.Childs[i]
|
|
||||||
if len(child.Keys) == 2*BTreeMinDegree-1 {
|
|
||||||
splitChild(node, i)
|
|
||||||
if key.Compare(node.Keys[i]) > 0 {
|
|
||||||
i++ // 选择正确的位置
|
|
||||||
}
|
|
||||||
}
|
|
||||||
insertNonFull(node.Childs[i], key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *BTree) Search(key IndexKey) (interface{}, bool) {
|
|
||||||
node := bt.Root
|
|
||||||
for node != nil {
|
|
||||||
// 在当前节点查找位置
|
|
||||||
i := 0
|
|
||||||
for i < len(node.Keys) && key.Compare(node.Keys[i]) > 0 {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.IsLeaf {
|
|
||||||
// 在叶子节点中查找精确匹配
|
|
||||||
if i < len(node.Keys) && key.Compare(node.Keys[i]) == 0 {
|
|
||||||
return node.Values[i], true
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
} else {
|
|
||||||
// 继续查找子节点
|
|
||||||
node = node.Childs[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *BTree) Delete(key IndexKey) {
|
|
||||||
deleteFromNode(bt.Root, key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从节点删除指定键
|
|
||||||
func deleteFromNode(node *BTreeNode, key IndexKey) {
|
|
||||||
minDegree := BTreeMinDegree
|
|
||||||
// 寻找键的位置
|
|
||||||
i := 0
|
|
||||||
for i < len(node.Keys) && key.Compare(node.Keys[i]) > 0 {
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
|
|
||||||
if node.IsLeaf {
|
|
||||||
// 叶子节点直接删除
|
|
||||||
if i < len(node.Keys) && key.Compare(node.Keys[i]) == 0 {
|
|
||||||
// 删除键值对
|
|
||||||
node.Keys = append(node.Keys[:i], node.Keys[i+1:]...)
|
|
||||||
node.Values = append(node.Values[:i], node.Values[i+1:]...)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 非叶子节点
|
|
||||||
if i < len(node.Keys) && key.Compare(node.Keys[i]) == 0 {
|
|
||||||
// 找到键,需要替换为后继值
|
|
||||||
child := node.Childs[i]
|
|
||||||
sibling := node.Childs[i+1]
|
|
||||||
|
|
||||||
if len(child.Keys) >= minDegree {
|
|
||||||
// 前驱节点存在,替换为前驱
|
|
||||||
predecessor := getPredecessor(child)
|
|
||||||
node.Keys[i] = predecessor
|
|
||||||
deleteFromNode(child, predecessor)
|
|
||||||
} else if len(sibling.Keys) >= minDegree {
|
|
||||||
// 后继节点存在,替换为后继
|
|
||||||
successor := getSuccessor(sibling)
|
|
||||||
node.Keys[i] = successor
|
|
||||||
deleteFromNode(sibling, successor)
|
|
||||||
} else {
|
|
||||||
// 合并节点
|
|
||||||
mergeNodes(node, i)
|
|
||||||
deleteFromNode(child, key)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 继续删除子节点
|
|
||||||
child := node.Childs[i]
|
|
||||||
if len(child.Keys) >= minDegree {
|
|
||||||
// 子节点足够大,继续删除
|
|
||||||
deleteFromNode(child, key)
|
|
||||||
} else {
|
|
||||||
// 需要重新平衡
|
|
||||||
if i > 0 && len(node.Childs[i-1].Keys) >= minDegree {
|
|
||||||
// 从左兄弟借
|
|
||||||
borrowFromLeft(node, i)
|
|
||||||
} else if i < len(node.Childs)-1 && len(node.Childs[i+1].Keys) >= minDegree {
|
|
||||||
// 从右兄弟借
|
|
||||||
borrowFromRight(node, i)
|
|
||||||
} else {
|
|
||||||
// 合并节点
|
|
||||||
if i > 0 {
|
|
||||||
mergeNodes(node, i-1)
|
|
||||||
} else {
|
|
||||||
mergeNodes(node, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
deleteFromNode(child, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取前驱节点
|
|
||||||
func getPredecessor(node *BTreeNode) IndexKey {
|
|
||||||
for !node.IsLeaf {
|
|
||||||
node = node.Childs[len(node.Childs)-1]
|
|
||||||
}
|
|
||||||
return node.Keys[len(node.Keys)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取后继节点
|
|
||||||
func getSuccessor(node *BTreeNode) IndexKey {
|
|
||||||
for !node.IsLeaf {
|
|
||||||
node = node.Childs[0]
|
|
||||||
}
|
|
||||||
return node.Keys[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并节点
|
|
||||||
func mergeNodes(parent *BTreeNode, index int) {
|
|
||||||
left := parent.Childs[index]
|
|
||||||
right := parent.Childs[index+1]
|
|
||||||
|
|
||||||
// 将左节点和右节点合并
|
|
||||||
left.Keys = append(left.Keys, parent.Keys[index])
|
|
||||||
left.Keys = append(left.Keys, right.Keys...)
|
|
||||||
|
|
||||||
if left.IsLeaf {
|
|
||||||
left.Values = append(left.Values, right.Values...)
|
|
||||||
left.Next = right.Next
|
|
||||||
if right.Next != nil {
|
|
||||||
right.Next.Prev = left
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
left.Childs = append(left.Childs, right.Childs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新父节点
|
|
||||||
parent.Keys = append(parent.Keys[:index], parent.Keys[index+1:]...)
|
|
||||||
parent.Childs = append(parent.Childs[:index+1], parent.Childs[index+2:]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从左兄弟借
|
|
||||||
func borrowFromLeft(parent *BTreeNode, index int) {
|
|
||||||
left := parent.Childs[index-1]
|
|
||||||
current := parent.Childs[index]
|
|
||||||
|
|
||||||
// 移动键
|
|
||||||
current.Keys = append([]IndexKey{parent.Keys[index-1]}, current.Keys...)
|
|
||||||
if !left.IsLeaf {
|
|
||||||
current.Childs = append([]*BTreeNode{left.Childs[len(left.Childs)-1]}, current.Childs...)
|
|
||||||
left.Childs = left.Childs[:len(left.Childs)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新父节点
|
|
||||||
parent.Keys[index-1] = left.Keys[len(left.Keys)-1]
|
|
||||||
left.Keys = left.Keys[:len(left.Keys)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从右兄弟借
|
|
||||||
func borrowFromRight(parent *BTreeNode, index int) {
|
|
||||||
current := parent.Childs[index]
|
|
||||||
right := parent.Childs[index+1]
|
|
||||||
|
|
||||||
// 移动键
|
|
||||||
current.Keys = append(current.Keys, parent.Keys[index])
|
|
||||||
parent.Keys[index] = right.Keys[0]
|
|
||||||
|
|
||||||
if !current.IsLeaf {
|
|
||||||
current.Childs = append(current.Childs, right.Childs[0])
|
|
||||||
right.Childs = right.Childs[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
right.Keys = right.Keys[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (bt *BTree) Traverse(cb func(key IndexKey) bool) []interface{} {
|
|
||||||
result := make([]interface{}, 0)
|
|
||||||
// 找到最左边的叶子节点
|
|
||||||
node := bt.Root
|
|
||||||
for node != nil && !node.IsLeaf {
|
|
||||||
node = node.Childs[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// 遍历所有叶子节点
|
|
||||||
for node != nil {
|
|
||||||
for i, key := range node.Keys {
|
|
||||||
if cb(key) {
|
|
||||||
result = append(result, node.Values[i])
|
|
||||||
} else {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node = node.Next
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type MultiFieldKey struct {
|
|
||||||
Fields []string
|
|
||||||
SortDirs []bool // true 表示降序
|
|
||||||
Values map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m MultiFieldKey) Compare(other IndexKey) int {
|
|
||||||
o := other.(MultiFieldKey)
|
|
||||||
for i, field := range m.Fields {
|
|
||||||
v1 := m.Values[field]
|
|
||||||
v2 := o.Values[field]
|
|
||||||
|
|
||||||
var cmp int
|
|
||||||
switch v1.(type) {
|
|
||||||
case string:
|
|
||||||
cmp = strings.Compare(v1.(string), v2.(string))
|
|
||||||
case float64:
|
|
||||||
if v1.(float64) < v2.(float64) {
|
|
||||||
cmp = -1
|
|
||||||
} else if v1.(float64) > v2.(float64) {
|
|
||||||
cmp = 1
|
|
||||||
} else {
|
|
||||||
cmp = 0
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic("Unsupported type")
|
|
||||||
}
|
|
||||||
|
|
||||||
if cmp != 0 {
|
|
||||||
if m.SortDirs[i] {
|
|
||||||
return -cmp
|
|
||||||
}
|
|
||||||
return cmp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "git.pyer.club/kingecg/godocdb/index"
|
||||||
|
|
||||||
|
type Index struct {
|
||||||
|
metadata index.IndexMetadata
|
||||||
|
store *index.IndexStore
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ func NewDocumentStore(storeName string) (*DocumentStore, error) {
|
||||||
storage.Close()
|
storage.Close()
|
||||||
return nil, fmt.Errorf("failed to create index store: %v", err)
|
return nil, fmt.Errorf("failed to create index store: %v", err)
|
||||||
}
|
}
|
||||||
if errCreate := is.CreateIndex("default_index", index.NonUnique, []string{"_id"}, []index.IndexSortOrder{index.Ascending}); errCreate != nil {
|
if _, errCreate := is.CreateIndex("default_index", index.NonUnique, []string{"_id"}, []index.IndexSortOrder{index.Ascending}); errCreate != nil {
|
||||||
return nil, errCreate
|
return nil, errCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ func (ds *DocumentStore) StoreDocument(collection string, id string, doc interfa
|
||||||
// 创建默认索引(如果不存在)
|
// 创建默认索引(如果不存在)
|
||||||
if _, err := ds.indexStore.GetIndexMetadata("default_index"); err != nil {
|
if _, err := ds.indexStore.GetIndexMetadata("default_index"); err != nil {
|
||||||
// 如果索引不存在,创建默认索引
|
// 如果索引不存在,创建默认索引
|
||||||
if errCreate := ds.indexStore.CreateIndex("default_index", index.NonUnique, []string{"_id"}, nil); errCreate != nil {
|
if _, errCreate := ds.indexStore.CreateIndex("default_index", index.NonUnique, []string{"_id"}, nil); errCreate != nil {
|
||||||
return errCreate
|
return errCreate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,13 +62,13 @@ func NewIndexStore(storeName string) (*IndexStore, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIndex 创建索引
|
// CreateIndex 创建索引
|
||||||
func (is *IndexStore) CreateIndex(indexName string, indexType IndexType, keyFields []string, sortOrders []IndexSortOrder) error {
|
func (is *IndexStore) CreateIndex(indexName string, indexType IndexType, keyFields []string, sortOrders []IndexSortOrder) (*IndexMetadata, error) {
|
||||||
is.mu.Lock()
|
is.mu.Lock()
|
||||||
defer is.mu.Unlock()
|
defer is.mu.Unlock()
|
||||||
|
|
||||||
// 验证keyFields和sortOrders长度一致
|
// 验证keyFields和sortOrders长度一致
|
||||||
if len(keyFields) != len(sortOrders) {
|
if len(keyFields) != len(sortOrders) {
|
||||||
return fmt.Errorf("keyFields and sortOrders must have the same length")
|
return nil, fmt.Errorf("keyFields and sortOrders must have the same length")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 存储索引元数据
|
// 存储索引元数据
|
||||||
|
@ -82,25 +82,26 @@ func (is *IndexStore) CreateIndex(indexName string, indexType IndexType, keyFiel
|
||||||
|
|
||||||
data, err := bson.Marshal(metadata)
|
data, err := bson.Marshal(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to marshal index metadata: %v", err)
|
return nil, fmt.Errorf("failed to marshal index metadata: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
key := []byte(fmt.Sprintf("indexes:metadata:%s", indexName))
|
key := []byte(fmt.Sprintf("indexes:metadata:%s", indexName))
|
||||||
if err := is.storage.Put(key, data); err != nil {
|
if err := is.storage.Put(key, data); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &metadata, nil
|
||||||
|
|
||||||
// 初始化索引结构
|
// // 初始化索引结构
|
||||||
index := make(map[string]string)
|
// index := make(map[string]string)
|
||||||
|
|
||||||
// 存储初始索引结构
|
// // 存储初始索引结构
|
||||||
indexKey := fmt.Sprintf("indexes:data:%s", indexName)
|
// indexKey := fmt.Sprintf("indexes:data:%s", indexName)
|
||||||
indexData, err := bson.Marshal(index)
|
// indexData, err := bson.Marshal(index)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return fmt.Errorf("failed to marshal index data: %v", err)
|
// return fmt.Errorf("failed to marshal index data: %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return is.storage.Put([]byte(indexKey), indexData)
|
// return is.storage.Put([]byte(indexKey), indexData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateIndex 在指定collection下更新索引
|
// UpdateIndex 在指定collection下更新索引
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestIndexStore(t *testing.T) {
|
||||||
keyFields := []string{"name"}
|
keyFields := []string{"name"}
|
||||||
|
|
||||||
// 测试创建索引(默认升序)
|
// 测试创建索引(默认升序)
|
||||||
if err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending}); err != nil {
|
if _, err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending}); err != nil {
|
||||||
t.Errorf("CreateIndex failed: %v", err)
|
t.Errorf("CreateIndex failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ func TestCompositeIndex(t *testing.T) {
|
||||||
keyFields := []string{"name", "age"}
|
keyFields := []string{"name", "age"}
|
||||||
|
|
||||||
// 创建复合索引(默认升序)
|
// 创建复合索引(默认升序)
|
||||||
if err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending, Ascending}); err != nil {
|
if _, err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending, Ascending}); err != nil {
|
||||||
t.Errorf("CreateIndex failed: %v", err)
|
t.Errorf("CreateIndex failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ func TestIndexSortOrder(t *testing.T) {
|
||||||
keyFields := []string{"timestamp"}
|
keyFields := []string{"timestamp"}
|
||||||
|
|
||||||
// 测试创建升序索引
|
// 测试创建升序索引
|
||||||
if err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending}); err != nil {
|
if _, err := is.CreateIndex(indexName, NonUnique, keyFields, []IndexSortOrder{Ascending}); err != nil {
|
||||||
t.Errorf("CreateIndex failed: %v", err)
|
t.Errorf("CreateIndex failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ func TestIndexSortOrder(t *testing.T) {
|
||||||
|
|
||||||
// 测试创建降序索引
|
// 测试创建降序索引
|
||||||
indexNameDesc := "sorted_index_desc"
|
indexNameDesc := "sorted_index_desc"
|
||||||
if err := is.CreateIndex(indexNameDesc, NonUnique, keyFields, []IndexSortOrder{Descending}); err != nil {
|
if _, err := is.CreateIndex(indexNameDesc, NonUnique, keyFields, []IndexSortOrder{Descending}); err != nil {
|
||||||
t.Errorf("CreateIndex failed: %v", err)
|
t.Errorf("CreateIndex failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ func TestCompositeIndexSortOrders(t *testing.T) {
|
||||||
sortOrders := []IndexSortOrder{Descending, Ascending}
|
sortOrders := []IndexSortOrder{Descending, Ascending}
|
||||||
|
|
||||||
// 创建复合索引
|
// 创建复合索引
|
||||||
if err := is.CreateIndex(indexName, NonUnique, keyFields, sortOrders); err != nil {
|
if _, err := is.CreateIndex(indexName, NonUnique, keyFields, sortOrders); err != nil {
|
||||||
t.Errorf("CreateIndex failed: %v", err)
|
t.Errorf("CreateIndex failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +206,7 @@ func TestConcurrentIndexOperations(t *testing.T) {
|
||||||
indexName := fmt.Sprintf("concurrent_index_%d", i)
|
indexName := fmt.Sprintf("concurrent_index_%d", i)
|
||||||
|
|
||||||
// 创建索引(默认升序)
|
// 创建索引(默认升序)
|
||||||
if err := is.CreateIndex(indexName, NonUnique, []string{"name"}, []IndexSortOrder{Ascending}); err != nil {
|
if _, err := is.CreateIndex(indexName, NonUnique, []string{"name"}, []IndexSortOrder{Ascending}); err != nil {
|
||||||
t.Errorf("CreateIndex failed: %v", err)
|
t.Errorf("CreateIndex failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue