Secondary index
Jump to the Code block for a combined complete example.
Basic SI queries can employ the following index filters:
- Equality comparison against string or numeric indexes.
- Range comparison against numeric indexes. Range result sets are inclusive of lower and upper limits.
- Point-In-Region or Region-Contain-Point comparisons against geo indexes.
Filter Expressions can also be used with secondary index queries.
Policies
See Basic Queries for query policy information.
Setup
The following examples will use the setup and record structure below to illustrate secondary index queries in an Aerospike database.
import ( "fmt" "github.com/aerospike/aerospike-client-go/v6")
// Establishes a connection to the serverclient, err := aerospike.NewClient("127.0.0.1", 3000)if err != nil { log.Fatal(err)}defer client.Close()
The record structure:
Occurred: IntegerReported: IntegerPosted: IntegerReport: Map{ shape: List, summary: String, city: String, state: String, duration: String}Location: GeoJSON
Create an index
The following command uses the Aerospike Admin (asadm) to create an integer index on the sandbox
namespace, ufodata
set, and occurred
bin. This is the recommended way to create a secondary index.
asadm -e 'enable; manage sindex create numeric occurred_idx ns sandbox set ufodata bin occurred'
The Aersopike Client API can be used to create a secondary index as well. The following example creates the same index as the example above.
// Create index tasktask, err := client.CreateIndex(nil, // write policy "sandbox", // namespace "ufodata", // set name "occurred_idx", // index name "occurred", // bin name aerospike.NUMERIC) // index typeif err != nil { log.Fatal(err)}
// Wait for the task to complete<-task.OnComplete()
In this example, the IndexType
is NUMERIC
. Aerospike supports index types NUMERIC
,STRING
, GEO2DSPHERE
, and BLOB
as of server 7.0.
Remove an index
The following command uses the Aerospike Admin (asadm) to remove the index created above.
asadm -e 'enable; manage sindex delete occurred_idx ns sandbox set ufodata'
The Aersopike Client API can be used to remove a secondary index as well. The following example removes the same index as the example above.
// Drop an indexerr := client.DropIndex(nil, // write policy "sandbox", // namespace "ufodata", // set name "occurred_idx") // index nameif err != nil { log.Fatal(err)}
Query an index
The following example queries the sandbox
namespace and ufodata
set name, with an inclusive range filter on the occurred
bin, returning records with a bin value between 20210101
and 20211231
.
// Create statementstmt := aerospike.NewStatement("sandbox", "ufodata")
// Create index filterstmt.SetFilter(aerospike.NewRangeFilter("occurred", 20210101, 20211231));
// Execute the queryrecordSet, err := client.Query(nil, stmt);if err != nil { log.Fatal(err)}
// Get the resultsfor records := range recordSet.Results() { if records != nil { // Do something fmt.Printf("Record: %v \\n", records.Record.Bins) }}
recordSet.Close()
Query an index with a Filter Expression
The following example will use the geo string defined in the expandable section below.
View the language specific data creation
// Create geo regionregion := "{ " +" \\"type\\": \\"Polygon\\", " +" \\"coordinates\\": [ " +" [ " +" [-109.061279296875, 36.97622678464096], " +" [-102.01904296874999, 36.97622678464096], " +" [-102.01904296874999, 41.0130657870063], " +" [-109.061279296875, 41.0130657870063], " +" [-109.061279296875, 36.97622678464096] " +" ] " +" ] " +"}"
This example queries the same namespace and set name, while using the same index filter as the example above, but adds a Filter Expression to the
query policy to only return records with a location
bin value within the geo region specified above.
// Create new query policyqueryPolicy := aerospike.NewQueryPolicy()queryPolicy.FilterExpression = aerospike.ExpGeoCompare( aerospike.ExpGeoBin("location"), aerospike.ExpGeoVal(region))
// Create statementstmt := aerospike.NewStatement("sandbox", "ufodata")
// Create index filterstmt.SetFilter(aerospike.NewRangeFilter("occurred", 20210101, 20211231))
// Execute the queryrecordSet, err := client.Query(queryPolicy, stmt)if err != nil { log.Fatal(err)}
// Get the resultsfor records := range recordSet.Results() { if records != nil { // Do something fmt.Printf("Record: %v \\n", records.Record.Bins) }}
recordSet.Close()
Query an index then create a batch operation on the returned keys
Currently, Transaction and CDT operations are not available for basic queries. The following example shows how a basic query and a batch operation can be combined to use transaction operations on the results.
This example queries the same namespace and set name, while using the same index filter, geo region, and Filter Expression as above, but
only returns record metadata, which is then used to create a batch operation to return only the city
and state
from the report
map.
// Create new query policyqueryPolicy := aerospike.NewQueryPolicy()queryPolicy.FilterExpression = aerospike.ExpGeoCompare( aerospike.ExpGeoBin("location"), aerospike.ExpGeoVal(region))
// do not include record binsqueryPolicy.IncludeBinData = false
// Create statementstmt := aerospike.NewStatement("sandbox", "ufodata")
// Create index filterstmt.SetFilter(aerospike.NewRangeFilter("occurred", 20210101, 20211231))
// Create keys listkeys := []*aerospike.Key{}
// Execute the queryrecordSet, err := client.Query(queryPolicy, stmt)if err != nil { log.Fatal(err)}
// Get the resultsfor records := range recordSet.Results() { if records != nil { keys = append(keys, records.Record.Key) }}
recordSet.Close()
// Create map key listmapKeys := []interface{}{"city", "state"}
// Get 'city' and 'state' from report map for each recordrecords, err := client.BatchGetOperate(nil, keys, aerospike.MapGetByKeyListOp("report", mapKeys, aerospike.MapReturnType.VALUE))if err != nil { log.Fatal(err)}
// Access the recordsfor _, record := range records { if record != nil { // Do something fmt.Printf("Record: %v \\n", record.Bins) }}
Pagination
See Pagination for more information.
Code block
Expand this section for a single code block to execute a basic SI query
import ( "fmt" "github.com/aerospike/aerospike-client-go/v6")
func main(){ // Establishes a connection to the server client, err := aerospike.NewClient("127.0.0.1", 3000) if err != nil { log.Fatal(err) } defer client.Close()
// Create geo region region := "{ " + " \\"type\\": \\"Polygon\\", " + " \\"coordinates\\": [ " + " [ " + " [-109.061279296875, 36.97622678464096], " + " [-102.01904296874999, 36.97622678464096], " + " [-102.01904296874999, 41.0130657870063], " + " [-109.061279296875, 41.0130657870063], " + " [-109.061279296875, 36.97622678464096] " + " ] " + " ] " + "}"
// Create new query policy queryPolicy := aerospike.NewQueryPolicy() queryPolicy.FilterExpression = aerospike.ExpGeoCompare( aerospike.ExpGeoBin("location"), aerospike.ExpGeoVal(region))
// Create statement stmt := aerospike.NewStatement("sandbox", "ufodata")
// Create index filter stmt.SetFilter(aerospike.NewRangeFilter("occurred", 20210101, 20211231))
// Execute the query recordSet, err := client.Query(queryPolicy, stmt) if err != nil { log.Fatal(err) }
// Get the results for records := range recordSet.Results() { if records != nil { // Do something fmt.Printf("Record: %v \\n", records.Record.Bins) } }
recordSet.Close()}