Couchbase Filter Query -> number in range between two numbers using Spring Data Couchbase (SpEL notation).) - spring

I'm trying to make a query in a Couchbase Database. The idea is to retrieve the elements which are in the range of two numbers. I'm using Spring Data Couchbase.
My query looks like this:
#Query("#{#n1ql.selectEntity} WHERE #{#n1ql.filter} AND $age BETWEEN minAge AND maxAge ")
Optional<Room> findByMinAgeAndMaxAge(#Param("age") int age);
But
Unable to execute query due to the following n1ql errors:
{"msg":"No index available on keyspace bucketEx that matches your query. Use CREATE INDEX or CREATE PRIMARY INDEX to create an index, or check that your expected index is online.","code":4000}
This is what I get in the console:
SELECT META(`bucketEx`).id AS _ID, META(`bucketEx`).cas AS _CAS, `bucketEx`.* FROM `bucketEx` WHERE `docType` = \"com.rccl.middleware.engine.repository.model.salon\" AND $age BETWEEN minAge AND maxAge ","$age":7,"scan_consistency":"statement_plus"}
My doubt is if I have to create the indexes for the two fields ( minAge AND maxAge) or there is another issue related with my query. I'm starting with Couchbase and not pretty sure of what is happening.
My document looks like this:
{
"salons": [
{
"name": "salon_0",
"id": "salon-00",
"maxAge": 6,
"minAge": 3
}
],
"docType": "com.rccl.middleware.engine.repository.model.salon"
}

The age you are looking is inside salons array. If you want document if any one of the array object matches you should use array index on on one of the filed.
CREATE INDEX ix1 ON bucketEx(DISTINCT ARRAY v.maxAge FOR v IN salons END)
WHERE `docType` = "com.rccl.middleware.engine.repository.model.salon";
SELECT META( b ).id AS _ID, META( b ).cas AS _CAS, b.*
FROM `bucketEx` AS b
WHERE b.`docType` = "com.rccl.middleware.engine.repository.model.salon" AND
ANY v IN b.salons SATISFIES $age BETWEEN v.minAge AND v.maxAge END;

Related

Update the value of a field in index based on its value in another index

There's an index_A that contains say about 10K docs. It has many fields like field_1, field_2, ...field_n and one of the fields is product_name.
Then there's another index_B that contains about 10 docs only and is a master catalogue sort of index. It has 2 fields: product_name and product_description.
e.g
{
"product_name" : "EES",
"product_desc" : "Elastic Enterprise Search"
}
{
"product_name" : "EO",
"product_desc" : "Elastic Observability"
}
index_A contains many fields, from that one of the fields is product_name. index_A does not have the field product_desc
I want to insert product_desc field into each document in index_A such that the value of product_name in index_A matches value of product_name in index_B.
i.e. something like set index_A.prod_desc = index_B.prod_desc where index_A.prod_name = index_B.prod_name
How can I achieve that?
Elasticsearch cannot do joins like that
the best approach would be to do this during indexing, using something like an ingest pipeline, or Logstash, or some other piece of code that pulls the description into the product document

FaunaDB search document and get its ranking based on a score

I have the following Collection of documents with structure:
type Streak struct {
UserID string `fauna:"user_id"`
Username string `fauna:"username"`
Count int `fauna:"count"`
UpdatedAt time.Time `fauna:"updated_at"`
CreatedAt time.Time `fauna:"created_at"`
}
This looks like the following in FaunaDB Collections:
{
"ref": Ref(Collection("streaks"), "288597420809388544"),
"ts": 1611486798180000,
"data": {
"count": 1,
"updated_at": Time("2021-01-24T11:13:17.859483176Z"),
"user_id": "276989300",
"username": "yodanparry"
}
}
Basically I need a lambda or a function that takes in a user_id and spits out its rank within the collection. rank is simply sorted by the count field. For example, let's say I have the following documents (I ignored other fields for simplicity):
user_id
count
abc
12
xyz
10
fgh
999
If I throw in fgh as an input for this lambda function, I want it to spit out 1 (or 0 if you start counting from 0).
I already have an index for user_id so I can query and match a document reference from this index. I also have an index sorted_count that sorts document based on count field ascendingly.
My current solution was to query all documents by sorted_count index, then get the rank by iterating through the array. I think there should be a better solution for this. I'm just not seeing it.
Please help. Thank you!
Counting things in Fauna isn't as easy as one might expect. But you might still be able to do something more efficient than you describe.
Assuming you have:
CreateIndex(
{
name: "sorted_count",
source: Collection("streaks"),
values: [
{ field: ["data", "count"] }
]
}
)
Then you can query this index like so:
Count(
Paginate(
Match(Index("sorted_count")),
{ after: 10, size: 100000 }
)
)
Which will return an object like this one:
{
before: [10],
data: [123]
}
Which tells you that there are 123 documents with count >= 10, which I think is what you want.
This means that, in order to get a user's rank based on their user_id, you'll need to implement this two-step process:
Determine the count of the user in question using your index on user_id.
Query sorted_count using the user's count as described above.
Note that, in case your collection has more than 100,000 documents, you'll need your Go code to iterate through all the pages based on the returned object's after field. 100,000 is Fauna's maximum allowed page size. See the Fauna docs on pagination for details.
Also note that this might not reflect whatever your desired logic is for resolving ties.

How can I combine multimatch query with a boolquery in elasticsearch?

I am trying to write a query that will run a query coupled with a multimatch query (possibly with an empty value) in elasticsearch. Consider the following data example where each item is a document in elasticsearch. Additional fields are redacted to reduce complexity in the example.
[
{
"name": "something",
"categories": ["python", "lib"]
},
{
"name": "test",
"categories": ["python", "lib"]
},
{
"name": "another",
"categories": ["javascript", "lib"]
}
]
What I am trying to do is writing a bool query where categories must match python and lib, and then run a multimatch query on that. So my code structure is:
// assume cat.Filter folds []string{"python", "lib"}
filters := []elastic.Query{}
for _, ff := range cat.Filter {
filters = append(filters, elastic.NewTermQuery("categories", ff))
}
// create multimatch query
e := elastic.NewMultiMatchQuery("something").Fuzziness("2")
// create a query that will match all fields in an array
q := elastic.NewBoolQuery().Must(filters...).Filter(e)
hits, err := client.Search().Index(index).Query(q).Size(limit).Do(ctx)
If I run this query with as is, then I get back 1 hit as expected. But if I change the multimatch query to e := elastic.NewMultiMatchQuery("some"), then I get back an empty array.
What I am trying to accomplish is:
When using e := elastic.NewMultiMatchQuery("some").Fuzziness("2"), return an array of 1 item that matches something
When I set e := elastic.NewMultiMatchQuery("").Fuzziness("2"), return an array of two items that match both categories for python and lib. (this works if i remove the multimatch array filter.
My issue is that I can do either or, but not both. I have a feeling because the Must is enforcing that something has to be an exact match, and some or "" does not match that. Thats what I am trying to overcome. First match all the values in an array, and then query that.

Merge Documents based on field value?

I have multiple Documents within an Index, each have the following fields:
id serviceName Type
Now, stupidly, id is not unique and I want to change that. I want to use Kibana/Elasticsearch to query the data so that I have id unique and the behaviour I want is that if I have the following Docs:
id serviceName Type
1 A T1
1 B T2
1 D T2
I use a query so that I get this result
1 A,B,C T1,T2,T3
Is there a way for this?
You cannot do this with just Elasticsearch/Kibana, you have to write some code. You can use the scroll api to iterate through all the documents in the index, and then use an upsert query to index them into a new index. I think your upsert request will look something like this:
POST test/type1/1/_update
{
"script" : {
"inline": "ctx._source.serviceName.add(params.serviceName); ctx._source.Type.add(params.Type)",
"lang": "painless",
"params" : {
"serviceName" : "A",
"Type": "T1"
}
},
"upsert" : {
"serviceName": ["A"],
"Type": ["T1"]
}
}
This means in case id 1 doesn't exist yet, add it with the "upsert" value for the document, otherwise do the script (which appends the serviceName and Type values to the existing doc).
This would be pretty straightforward to do with very little code using elasticsearch-py, check out the scan helper and bulk helper

How to get the total documents count, containing a specific field, using aggregations?

I am moving from ElasticSearch 1.7 to 2.0. Previously while calculating Term Facets I got the Total Count as well. This will tell in how many documents that field exists. This is how I was doing previously.
TermsFacet termsFacet = (TermsFacet) facet;
termsFacet.getTotalCount();
It worked with Multivalue field as well.
Now in current version for Term Aggregation we don't have anything as Total Count. I am getting DocCount inside Aggregation bucket. But that will not work for muti-valued fields.
Terms termsAggr = (Terms) aggr;
for (Terms.Bucket bucket : termsAggr.getBuckets()) {
String bucketKey = bucket.getKey();
totalCount += bucket.getDocCount();
}
Is there any way I can get Total count of the field from term aggregation.
I don't want to fire exists Filter query. I want result in single query.
I would use the exists query:
https://www.elastic.co/guide/en/elasticsearch/reference/2.x/query-dsl-exists-query.html
For instance to find the documents that contain the field user you can use:
{
"exists" : { "field" : "user" }
}
There is of course also a java API:
https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-term-level-queries.html#java-query-dsl-exists-query
QueryBuilder qb = existsQuery("name");

Resources