英文:
How to get record from Aerospike by iterating through LIST
问题
我有一个接近这样的数据库结构:
+--------------+---------+------------------------------+
| hostname | cont | numbers |
+--------------+---------+------------------------------+
| host01 |{"k":"v"}|LIST([[1, 123456, ...]])|
| host02 |{"k":"v"}|LIST([[1, 654321, ...]])|
+--------------+---------+------------------------------+
我想通过筛选"Numbers"和"Hostname"来获取特定的记录。它应该包含一个特定数字的字符串,该数字来自其他组件。在上面的代码中,它是'123456'。
基本上,我以前是这样搜索的,直到需要二维数组:
stmt := aerospike.NewStatement(namespaceName, setName)
stmt.SetPredExp(
aerospike.NewPredExpStringBin("hostname"),
aerospike.NewPredExpStringValue(inputHostName),
aerospike.NewPredExpStringRegex(0),
aerospike.NewPredExpStringBin("deleted"),
aerospike.NewPredExpStringValue("true"),
aerospike.NewPredExpStringEqual(),
aerospike.NewPredExpNot(),
aerospike.NewPredExpAnd(2))
)
我一直在寻找通过数组进行筛选的方法,但没有找到任何解决方案。
我在互联网上找到的方法是这样的:
stmt := aerospike.NewStatement("test", "settest")
qPolicy := aerospike.NewQueryPolicy()
qPolicy.PredExp = append(qPolicy.PredExp,
aerospike.NewPredExpStringVar("v"),
aerospike.NewPredExpStringValue(id),
aerospike.NewPredExpStringEqual(),
aerospike.NewPredExpListBin("numbers"),
aerospike.NewPredExpListIterateOr("v"))
recordSet, err := aerospikeClient.client.Query(qPolicy, stmt)
但它不起作用。
如果我提供了使用主机名和某种方式解析数组的谓词表达式,是否可以搜索记录?
更新:
我发现,可以通过使用过滤表达式来解决这个问题,特别是使用CDTContext。但是,Aerospike文档对于使用这个工具的信息非常有限,尤其是关于Go代码的使用。我只找到了这个可能有帮助的方法,但我不知道如何在我的情况下正确使用它:
func aerospike.ExpListGetByValue(returnType aerospike.ListReturnType, value *aerospike.Expression, bin *aerospike.Expression, ctx ...*aerospike.CDTContext) *aerospike.Expression
更新2:
通过使用ExpListGetByValue,我尝试进行查询,但它找不到任何内容。它看起来像这样:
stmt := aerospike.NewStatement(namespaceName, setName)
qPolicy := aerospike.NewQueryPolicy()
qPolicy.FilterExpression = aerospike.ExpEq(
aerospike.ExpListGetByValue(
aerospike.ListReturnTypeCount,
aerospike.ExpStringVal(numbVal),
aerospike.ExpListBin("numbers")),
aerospike.ExpIntVal(1))
recordSet, err := aerospikeClient.client.Query(qPolicy, stmt)
这个recordSet
是空的,尽管"numbers" bin确实包含这个numVal
。
更新3:
问题已解决。我为嵌套数组添加了上下文。完整的过滤表达式如下:
qPolicy.FilterExpression = aerospike.ExpEq(
aerospike.ExpListGetByValue(
aerospike.ListReturnTypeCount,
aerospike.ExpStringVal("123456"),
aerospike.ExpListBin("numbers"),
aerospike.CtxListIndex(-1)),
aerospike.ExpIntVal(1))
英文:
I have database structure, close to this:
+--------------+---------+------------------------------+
| hostname | cont | numbers |
+--------------+---------+------------------------------+
| host01 |{"k":"v"}|LIST(`[["1", "123456", ...]]`)|
| host02 |{"k":"v"}|LIST(`[["1", "654321", ...]]`)|
+--------------+---------+------------------------------+
I want to get certain record, by filtering bin "Numbers" and "Hostname".
It should contain a string with certain number, that I get from other component. In code above, it's '123456'
Basically, I used to search it in this way, until two-dimensional array is required:
stmt := aerospike.NewStatement(namespaceName, setName)
stmt.SetPredExp(
aerospike.NewPredExpStringBin("hostname"),
aerospike.NewPredExpStringValue(inputHostName),
aerospike.NewPredExpStringRegex(0),
aerospike.NewPredExpStringBin("deleted"),
aerospike.NewPredExpStringValue("true"),
aerospike.NewPredExpStringEqual(),
aerospike.NewPredExpNot(),
aerospike.NewPredExpAnd(2))
)
I've been looking though possible way to filter through array, but didn't get any solutions.
The way I found on the Internet was something like this:
stmt := aerospike.NewStatement("test", "settest")
qPolicy := aerospike.NewQueryPolicy()
qPolicy.PredExp = append(qPolicy.PredExp,
aerospike.NewPredExpStringVar("v"),
aerospike.NewPredExpStringValue(id),
aerospike.NewPredExpStringEqual(),
aerospike.NewPredExpListBin("numbers"),
aerospike.NewPredExpListIterateOr("v"))
recordSet, err := aerospikeClient.client.Query(qPolicy, stmt)
But it doesn't work.
Is it possible to search for Record, if I'll provide Predicated Expression using both hostname, and somehow parse array?
UPD:
I found out, this case can be solved by using Filter Expression, especially with usage of CDTContext. But Aerospike documentation has very poor information about usage of this tool, especially on Go code.
I found only this method, which could help, but I don't understand how to use it correctly in my case:
func aerospike.ExpListGetByValue(returnType aerospike.ListReturnType, value *aerospike.Expression, bin *aerospike.Expression, ctx ...*aerospike.CDTContext) *aerospike.Expression
UPD2
By using ExpListGetByValue I've tried to make a query, but it couldn't find anything. It looks like this:
stmt := aerospike.NewStatement(namespaceName, setName)
qPolicy := aerospike.NewQueryPolicy()
qPolicy.FilterExpression = aerospike.ExpEq(
aerospike.ExpListGetByValue(
aerospike.ListReturnTypeCount,
aerospike.ExpStringVal(numbVal),
aerospike.ExpListBin("numbers")),
aerospike.ExpIntVal(1))
recordSet, err := aerospikeClient.client.Query(qPolicy, stmt)
This recordSet
comes empty, though "numbers" bin do contain this numVal
UPD3
The problem was solved. I added context for nested array. Complete Filter expression will look like this
qPolicy.FilterExpression = aerospike.ExpEq(
aerospike.ExpListGetByValue(
aerospike.ListReturnTypeCount,
aerospike.ExpStringVal("123456"),
aerospike.ExpListBin("numbers"),
aerospike.CtxListIndex(-1)),
aerospike.ExpIntVal(1))
答案1
得分: 3
我正在运行你的测试,使用你在第二次更新中创建的新的修订过的过滤器,看起来它是有效的。以下是我使用的完整代码(基于Git存储库中的Aerospike示例目录):
/*
* Copyright 2014-2022 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package main
import (
"log"
as "github.com/aerospike/aerospike-client-go/v5"
shared "github.com/aerospike/aerospike-client-go/v5/examples/shared"
)
func main() {
testListExp(shared.Client)
log.Println("Example finished successfully.")
}
func testListExp(client *as.Client) {
log.Printf("Test List Expression")
key, _ := as.NewKey(*shared.Namespace, *shared.Set, "mapkey1")
client.Delete(shared.WritePolicy, key)
binHostname := as.NewBin("hostname", "host01")
amap := map[string]string{
"k": "v",
}
list := []string{
"1",
"123456",
"1111",
"222",
}
binCont := as.NewBin("cont", amap)
binNumbers := as.NewBin("numbers", list)
client.PutBins(shared.WritePolicy, key, binHostname, binCont, binNumbers)
key, _ = as.NewKey(*shared.Namespace, *shared.Set, "mapkey2")
binHostname = as.NewBin("hostname", "host02")
list = []string{
"1",
"654321",
"2222",
"3333",
}
binNumbers = as.NewBin("numbers", list)
client.PutBins(shared.WritePolicy, key, binHostname, binCont, binNumbers)
// numbVal := "654321"
getPolicy := as.NewQueryPolicy()
getPolicy.FilterExpression =
as.ExpEq(
as.ExpListGetByValue(
as.ListReturnTypeCount,
as.ExpStringVal("654321"),
as.ExpListBin("numbers")),
as.ExpIntVal(1))
stmt := as.NewStatement(*shared.Namespace, *shared.Set)
recordSet, err := client.Query(getPolicy, stmt)
shared.PanicOnError(err)
for res := range recordSet.Results() {
log.Println(res.Record.Bins)
}
}
输出结果为:
$ go run listExpression.go -h 172.17.0.3
2022/06/08 12:00:19 hosts: 172.17.0.3
2022/06/08 12:00:19 port: 3000
2022/06/08 12:00:19 user:
2022/06/08 12:00:19 password: *
2022/06/08 12:00:19 namespace: test
2022/06/08 12:00:19 set: testset
2022/06/08 12:00:19 Test List Expression
2022/06/08 12:00:19 map[cont:map[k:v] hostname:host02 numbers:[1 654321 2222 3333]]
2022/06/08 12:00:19 Example finished successfully.
英文:
I was running your test with the new-and-revised filter you created in your second update and it seems to work. Here is the full code I used (based on the Aerospike Example directory from the Git repo):
/*
* Copyright 2014-2022 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package main
import (
"log"
as "github.com/aerospike/aerospike-client-go/v5"
shared "github.com/aerospike/aerospike-client-go/v5/examples/shared"
)
func main() {
testListExp(shared.Client)
log.Println("Example finished successfully.")
}
func testListExp(client *as.Client) {
log.Printf("Test List Expression")
key, _ := as.NewKey(*shared.Namespace, *shared.Set, "mapkey1")
client.Delete(shared.WritePolicy, key)
binHostname := as.NewBin("hostname", "host01")
amap := map[string]string{
"k": "v",
}
list := []string{
"1",
"123456",
"1111",
"222",
}
binCont := as.NewBin("cont", amap)
binNumbers := as.NewBin("numbers", list)
client.PutBins(shared.WritePolicy, key, binHostname, binCont, binNumbers)
key, _ = as.NewKey(*shared.Namespace, *shared.Set, "mapkey2")
binHostname = as.NewBin("hostname", "host02")
list = []string{
"1",
"654321",
"2222",
"3333",
}
binNumbers = as.NewBin("numbers", list)
client.PutBins(shared.WritePolicy, key, binHostname, binCont, binNumbers)
// numbVal := "654321"
getPolicy := as.NewQueryPolicy()
getPolicy.FilterExpression =
as.ExpEq(
as.ExpListGetByValue(
as.ListReturnTypeCount,
as.ExpStringVal("654321"),
as.ExpListBin("numbers")),
as.ExpIntVal(1))
stmt := as.NewStatement(*shared.Namespace, *shared.Set)
recordSet, err := client.Query(getPolicy, stmt)
shared.PanicOnError(err)
for res := range recordSet.Results() {
log.Println(res.Record.Bins)
}
}
and the output was:
$ go run listExpression.go -h 172.17.0.3
2022/06/08 12:00:19 hosts: 172.17.0.3
2022/06/08 12:00:19 port: 3000
2022/06/08 12:00:19 user:
2022/06/08 12:00:19 password: *
2022/06/08 12:00:19 namespace: test
2022/06/08 12:00:19 set: testset
2022/06/08 12:00:19 Test List Expression
2022/06/08 12:00:19 map[cont:map[k:v] hostname:host02 numbers:[1 654321 2222 3333]]
2022/06/08 12:00:19 Example finished successfully.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论