Solr - Search parent having multiple child documents - solr

I have a Solr index with structure as below.
{
"id": "1",
"bookName_s": "Core Concepts",
"bookDescription_s": "This is the description",
"isbn_s": "ABCD:123",
"reviews": [
{
"id": "2",
"Name_s": "review1",
"detail_s": "sample review"
}
],
"students": [
{
"id": "3",
"Name_s": "student1",
"student_s": "test student"
}
]
}
How do i search for parent that has a reviewer with Name_s as 'review1' and student with Name_s as 'student'.
I tried parent block chain query like below but nothing seems to work -
q=({!parent which="*:* -_nest_path_:*"}(+_nest_path_:\/reviews +Name_s:*rev*)) AND ({!parent which="*:* -_nest_path_:*"}(+_nest_path_:\/students +Name_s:*stu*))
q=({!parent which="*:* -_nest_path_:*"}(+_nest_path_:\/reviews +Name_s:*rev*)(+_nest_path_:\/students +Name_s:*stu*))
Is there a way i can acheive this using the q operator instead of fq parameter? thanks

Based on EricLavault suggestion i modified the index to include type of the object in the index like below -
{
"id": "1",
"bookName_s": "Core Concepts",
"bookDescription_s": "This is the description",
"isbn_s": "ABCD:123",
"type_s":"book"
"reviews": [
{
"id": "2",
"Name_s": "review1",
"detail_s": "sample review",
"type":"review"
}
],
"students": [
{
"id": "3",
"Name_s": "student1",
"type":"student",
"student_s": "test student"
}
]
}
and below queries worked.
{!parent which="type:book"}(type:review AND Name_s:review1) OR (type:student AND Name_s:student1)
returns all books with review1 and student1

Related

How to update object fields inside nested array and dynamically set a field value based on some inputs

I have been working on a Mongo database for a while. The database has some visits that have this form:
[
{
"isPaid": false,
"_id": "5c12bc3dcea46f9d3658ca98",
"clientId": "5c117f2d1d6b9f9182182ae4",
"came_by": "Twitter Ad",
"reason": "Some reason",
"doctor_services": "Some service",
"doctor": "Dr. Michael",
"service": "Special service",
"payments": [
{
"date": "2018-12-13T21:23:05.424Z",
"_id": "5c12cdb9b236c59e75fe8190",
"sum": 345,
"currency": "$",
"note": "First Payment"
},
{
"date": "2018-12-13T21:23:07.954Z",
"_id": "5c12cdbbb236c59e75fe8191",
"sum": 100,
"currency": "$",
"note": "Second payment"
},
{
"date": "2018-12-13T21:23:16.767Z",
"_id": "5c12cdc4b236c59e75fe8192",
"sum": 5,
"currency": "$",
"note": "Third Payment"
}
],
"price": 500,
"createdAt": "2018-12-13T20:08:29.425Z",
"updatedAt": "2018-12-13T21:42:21.559Z",
}
]
I need to find some query to update some field of a single payment based on the _id of the visit and _id of the payment that is inside of nested array. Also when you update a payment's sum to some number so that the sum of all payments is greater than or equal to price the field isPaid is automatically updated to true.
I have tried some queries in mongoose to achieve the first part but none of them seem to work:
let paymentId = req.params.paymentId;
let updatedFields = req.body;
Visit.update(
{ "payments._id": paymentId },
{
$set: {
"visits.$": updatedFields
}
}
).exec((err, visit) => {
if (err) {
return res.status(500).send("Couldn't update payment");
}
return res.status(200).send("Updated payment");
});
As for the second part of the question I haven't really come up with anything so I would appreciate at least giving some direction on how to approach it.

Is it possible to apply a solr document int field value as boost value if a specific field is matched?

Ex.
"docs": [
{
"id": "f37914",
"index_id": "some_index",
"field_1": [
{
"Some value",
"boost": 20.
}
]
},
]
If 'field_1' is matched, then boost by corresponding 'boost' field.
Boost what? the document? the specific field? you can do any of them.
Anyway the way to do it is to user Function Queries:
https://lucene.apache.org/solr/guide/6_6/function-queries.html#FunctionQueries-AvailableFunctions
For example if you want to boost the document (and assuming if the value doesn't match then the score is 0) then you can do something like that:
q:_val_:"if(query($q1), field(boost), 0)"&q1=field_1:"Some Value"
_val_ is just a hook into Solr function query, query returns true if q1 matches, field is a simple function that just return the value of the field it self and if allows us to join the two together.
So what I ended up doing is using lucence payloads and solr 6.6 new DelimitedPayloadTokenFilter feature.
First I created a terms field with the following configuration:
{
"add-field-type": {
"name": "terms",
"stored": "true",
"class": "solr.TextField",
"positionIncrementGap": "100",
"indexAnalyzer": {
"tokenizer": {
"class": "solr.KeywordTokenizerFactory"
},
"filters": [
{
"class": "solr.LowerCaseFilterFactory"
},
{
"class": "solr.DelimitedPayloadTokenFilterFactory",
"encoder": "float",
"delimiter": "|"
}
]
},
"queryAnalyzer": {
"tokenizer": {
"class": "solr.KeywordTokenizerFactory"
},
"filters": [
{
"class": "solr.LowerCaseFilterFactory"
},
{
"class": "solr.SynonymGraphFilterFactory",
"ignoreCase": "true",
"expand": "false",
"tokenizerFactory": "solr.KeywordTokenizerFactory",
"synonyms": "synonyms.txt"
}
]
}
},
"add-field" : {
"name":"terms",
"type":"terms",
"stored": "true",
"multiValued": "true"
}
}
I indexed my documents likes so:
[
{
"id" : "1",
"terms" : [
"some term|10.0",
"another term|60.0"
]
}
,
{
"id" : "2",
"terms" : [
"some term|11.0",
"another term|21.0"
]
}
]
I used solr's functional query support to query for a match on terms and grab the attached boost payload and apply it to the relevancy score:
/solr/payloads/select?indent=on&wt=json&q={!payload_score%20f=ai_terms_wtih_synm_3%20v=$payload_term%20func=max}&fl=id,score&payload_term=some+term

How to use OData filter in dynamic array

I am trying to filter nested array using ?$filter in odata filter
but it is not working properly
parent array got filtered but not child one.
My Array
{
"value": [
{
"Id": 1,
"Country": "India",
"language": [
{
"Lid": 1,
"State": "telengana",
"Statuelanguage": "Telgu",
"Place to visit": [
"p3","p4"
]
},
{
"Lid": 2,
"State": "Delhi",
"Statuelanguage": "Hindi",
"Place to visit": [
"p5","p6"
]
},
{
"Lid": 3,
"State": "UP",
"Statuelanguage": "Hindi",
"Place to visit": [
"p7","p8"
]
}
]
}
]
}
Expected Responce
{
"value": [
{
"Id": 1,
"Country": "India",
"language": [
{
"Lid": 1,
"State": "telengana",
"Statuelanguage": "Telgu",
"Place to visit": [
"p3","p4"
]
}
]
}
]
}
Filter query
?$filter=language/any(c: c/Lid eq 1)
but when i am trying to use the filter, it is filtering the parent one not the child
it returns all 3 child to me
So it works as expected :)
$filter parameter is used to filter collection that you're querying.
To filter expanded/related collection (language in your case) you have to use expand filter feature:
...$expand=language($filter=Lid eq 1)
BUT: It is only possible in OData v4.
ref for webapi
nested filter description

Unique Filter to Elastic Search Column not working (duplicate items inserted)

I've modified my contactNumber field to have a unique filter
by updating the index settings as follows
curl -XPUT localhost:9200/test-index2/_settings -d '
{
"index":{
"analysis":{
"analyzer":{
"unique_keyword_analyzer":{
"only_on_same_position":"true",
"filter":"unique"
}
}
}
},
"mappings":{
"business":{
"properties":{
"contactNumber":{
"analyzer":"unique_keyword_analyzer",
"type":"string"
}
}
}
}
}'
A sample Item looks like this,
doc_type:"Business"
contactNumber:"(+12)415-3499"
name:"Sam's Pizza"
address:"Somewhere on earth"
The Filter does not work, as duplicate items are inserted, I'd like NO two documents having the same contactNumber
in the above, I've also set only_on_same_position -> true so that existing duplicate values would be truncated/deleted
What am i doing wrong in the settings?
That's something Elasticsearch couldn't help you out of the box... you need to make this uniqueness functionality available in your app. The only idea that I can think of is to have the phone number as the _id of the document itself and whenever you insert/update something ES will use the contactNumber as _id and it will associate that document with the one that already exists or create a new one.
For example:
PUT /test-index2
{
"mappings": {
"business": {
"_id": {
"path": "contactNumber"
},
"properties": {
"contactNumber": {
"type": "string",
"analyzer": "keyword"
},
"address": {
"type": "string"
}
}
}
}
}
Then you index something:
POST /test-index2/business
{
"contactNumber": "(+12)415-3499",
"address": "whatever 123"
}
Getting it back:
GET /test-index2/business/_search
{
"query": {
"match_all": {}
}
}
It looks like this:
"hits": {
"total": 1,
"max_score": 1,
"hits": [
{
"_index": "test-index2",
"_type": "business",
"_id": "(+12)415-3499",
"_score": 1,
"_source": {
"contactNumber": "(+12)415-3499",
"address": "whatever 123"
}
}
]
}
You see there that the _id of the document is the phone number itself. If you want to change or insert another document (the address is different, there is a new field - whatever_field - but the contactNumber is the same):
POST /test-index2/business
{
"contactNumber": "(+12)415-3499",
"address": "whatever 123 456",
"whatever_field": "whatever value"
}
Elasticserach "updates" the existing document and responds back with:
{
"_index": "test-index2",
"_type": "business",
"_id": "(+12)415-3499",
"_version": 2,
"created": false
}
created is false, this means the document has been updated, not created. _version is 2 which again says that the document has been updated. And the _id is the phone number itself which indicate this is the document that has been updated.
Looking again in the index, ES stores this:
"hits": [
{
"_index": "test-index2",
"_type": "business",
"_id": "(+12)415-3499",
"_score": 1,
"_source": {
"contactNumber": "(+12)415-3499",
"address": "whatever 123 456",
"whatever_field": "whatever value"
}
}
]
So, the new field is there, the address has changed, the contactNumber and _id are exactly the same.

Retrieve elements from MongoDB

I've been looking at some StackOverflow cases such as this case, but I cannot find an example with a document structure close to this one.
Below is an example of one document within my collection artistTags. All documents follow the same structure.
{
"_id": ObjectId("5500aaeaa7ef65c7460fa3d9"),
"toptags": {
"tag": [
{
"count": "100",
"name": "Hip-Hop"
},
{
"count": "97",
"name": "french rap"
},
...{
"count": "0",
"name": "seen live"
}
],
"#attr": {
"artist": "113"
}
}
}
1) How can I find() this document using the "artist" value (here "113")?
2) How can I retrieve all "artist" values having a specific "name" value (say "french rap") ?
Referring to chridam answer here above:
db.collection.find({"toptags.#attr.artist": "113"})

Resources