ElasticSearch More_Like_This API and Nested Object Properties - search

I'm fairly new to ES so forgive me if this is a common scenario that I haven't discovered yet.
I've got an index which contains documents and each document can be related to a specific event, so I have a nested event object in each document. Event -> Document is a one-to-many relationship.
When I am displaying a single document, I want to show "More like this" where more-like-this actually represents more documents from the same meeting, by the same author, or on the same topic.
Author and Topic work fine, but although mlt_fields accepts "event.title" as a fieldname, it doesn't ever find any documents from the same event.
My mapping:
{
"myindex": {
"mappings": {
"myitem": {
"properties": {
"authors": {
"type": "string",
"analyzer": "keyword"
},
"id": {
"type": "integer"
},
"title": {
"type": "string"
},
"topics": {
"type": "string",
"analyzer": "keyword"
},
"event": {
"type": "nested",
"properties": {
"title": {
"type": "string",
"analyzer": "keyword"
},
...
}
}
}
}
}
}
}
My Query:
GET /myindex/mydoc/7/_mlt?mlt_fields=event.title&min_doc_freq=1&min_term_freq=1&percent_terms_to_match=0
{
"from": 0,
"size": 5
}
My Results:
{
...
"hits": {
"total": 0,
"max_score": null,
"hits": []
}
}
I suspect this is a nesting thing, so do I have to create a nested filtered query with "event = my_event" OR more-like-this = "author or topic" ? Or am I just missing something really stupid ?

Yes, you have to do a nested query to query nested fields:
Because nested docs are always masked to the parent doc, the nested docs can never be accessed outside the scope of the nested query.
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-nested-type.html
http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html

Related

Unable to retrieve a document from Mongo (using mongoose) with a partial match

I have a project in NodeJS (v16.14.0) in which I want to filter a list of documents. Most of the attributes are string and such they are easy to access yet, with the specialty (obj) attribute I am not able to get the info that I want:
{
"_id": {
"$oid": "--"
},
"name": "string",
"email": "string",
"password": "string",
"phoneNumber": "number",
"city": "string",
"myDescription": "string",
"specialty": {
"certified": ["plomero","electricista"],
"inProgress": ["albañil"],
"nonCertified": ["mecanico","veterinario"]
},
"image": {
"profile": [
"string",
"string"
],
"myJobs": [
"string",
"string"
]
},
"socialSecurity": {
"eps": "string",
"arl": "string"
},
"availability": {
"schedule": "string",
"fullAvailability": false
}
}
I want to use a string and return a list of documents that contain the given string in the certified attribute, for example:
db.collection.find({ specialty: { certified: { $in: ['plomero'] } } })
// return the document shown above
But I always get nothing. I have tried using $in and $elemMatch with no results. I can only retrieve the document as long as I copy the entire object:
db.collection.find({ specialty: { certified: ['plomero', 'electricista'], inProgress: ['albañil'], nonCertified: ['mecanico', 'veterinario'] } })
I have no clue on how to proceed, I have been reading MongoDB documentation but cannot find an example similar to this... Also I am quite new with Mongo.
Thanks for any guidance!
use find
db.collection.find({
"specialty.certified": "plomero"
})
mongoplayground

Include `meta` member in resource identifiers in `relationships` object

From my understanding of the JSON:API spec (specifically https://jsonapi.org/format/#document-resource-object-linkage) I should be able to include meta members for each member of a relationship.
I have been able to add a hash of meta data to the relationships object itself, but not one to each of the individual relationships within.
class PlanSerializer < ApplicationSerializer
attributes :id, :name
has_many :features do
meta value: "x"
end
end
I know I can use a block syntax for has_many, and think that's the way to achieve this. But I haven't got it working. Calling the meta method within the block adds the meta block to the features relationship object, and I need to add one to each entry in that array.
My questions:
Have I understood the spec correctly? Should I be able to add a meta object to each relationship?
How would I go about doing this with the active model serializers?
Background:
My goal is to represent a many-many from Plans to Features where each plan might have some extra information for it's own relationship to a given Feature (and that information is different for every Plan, so it doesn't belong on the Feature object)
If your answer is that I shouldn't be doing this, that's fine, but please present an alternative which you think is preferred.
// My desired output
{
"data": [
{
"id": "small",
"type": "plans",
"attributes": {
/* Some attributes */
},
"relationships": {
"features": {
"data": [
{
"id": "num-users",
"type": "features",
"meta": {
"value": 1
}
},
{
"id": "num-projects",
"type": "features",
"meta": {
"value": 5
}
}
]
}
}
},
{
"id": "large",
"type": "plans",
"attributes": {
/* Some attributes */
},
"relationships": {
"features": {
"data": [
{
"id": "num-users",
"type": "features",
"meta": {
"value": 5
}
},
{
"id": "num-projects",
"type": "features",
"meta": {
"value": 50
}
},
{
"id": "unlimited-downloads",
"type": "features"
}
]
}
}
}
],
"included": [
{
"id": "num-users",
"type": "features",
"attributes": {
"description": "Number of users"
}
},
{
"id": "num-projects",
"type": "features",
"attributes": {
"description": "Number of projects"
}
},
{
"id": "unlimited-downloads",
"type": "features",
"attributes": {
"description": "Unlimited downloads"
}
}
]
}

Commercetools - Use query predicates to filter on a collection attribute

I'd like to get all the Category items that have between their ancestors an ancestor with a certain "id".
Here is the JSON of one of the categories returned by GETting from /categories:
{
"id": "4627f3b0-fe52-4cc6-b03e-3fd72e701342",
"version": 1,
"lastMessageSequenceNumber": 1,
"createdAt": "2019-02-18T13:48:51.677Z",
"lastModifiedAt": "2019-02-18T13:48:51.677Z",
"lastModifiedBy": {
"clientId": "_anonymous"
},
"createdBy": {
"clientId": "_anonymous"
},
"key": "snowboard-gloves",
"name": {
"en": "Snowboard Gloves"
},
"slug": {
"en": "snowboard-gloves"
},
"description": {
"en": "Gloves specifically designed for snowboarding"
},
"ancestors": [
{
"typeId": "category",
"id": "b27086d2-33f2-43c3-aad1-4c01b2b9a886"
}
],
"parent": {
"typeId": "category",
"id": "b27086d2-33f2-43c3-aad1-4c01b2b9a886"
},
"orderHint": "0.000016",
"metaTitle": {
"en": "Snowboard Gloves"
},
"metaDescription": {
"en": "Gloves specifically designed for snowboarding"
},
"assets": []
}
I'd like to call the /categories API with a where clause on ancestors[x].id = "b27086d2-33f2-43c3-aad1-4c01b2b9a886" but from the documentation I don't understand how I should write the query predicate.
Can anyone help me?
The query predicate follows the structure of the json response. Nested fields are accessed with () brackets.
Try this out
ancestors(id = "idb27086d2-33f2-43c3-aad1-4c01b2b9a886")

Elastic Search: Dynamic Template Mapping for Geo Point Field

Is dynamic mapping for geo point still working in Elastic Search 2.x/5.x?
This is the template:
{
"template": "*",
"mappings": {
"_default_": {
"dynamic_templates": [
{
"geo_point_type": {
"match_mapping_type": "string",
"match": "t_gp_*",
"mapping": {
"type": "geo_point"
}
}
}
]
}
}
}
This is the error I get when I query the field:
"reason": "failed to parse [geo_bbox] query. field [t_gp_lat-long#en] is expected to be of type [geo_point], but is of [string] type instead"
I seems to remember that I saw somewhere in the documentation that this doesn't work, but I thought that's only when there is no dynamic template at all.
Any idea?
Update 1
Here's a sample of the document. The actual document is very big so I took the only relevant part of it.
{
"_index": "route",
"_type": "route",
"_id": "583a014edd76239997fca5e4",
"_score": 1,
"_source": {
"t_b_highway#en": false,
"t_n_number-of-floors#en": 33,
"updatedBy#_id": "58059fe368d0a739916f0888",
"updatedOn": 1480196430596,
"t_n_ceiling-height#en": 2.75,
"t_gp_lat-long#en": "13.736248,100.5604997"
}
}
Data looks correct to me since you can also index Geo Point field with lat/long string.
Update 2
Mapping is definitely wrong. That's why I'm wondering if you can dynamically map Geo Point field.
"t_gp_lat-long#en": {
"type": "string",
"fields": {
"english": {
"type": "string",
"analyzer": "english"
},
"raw": {
"type": "string",
"index": "not_analyzed",
"ignore_above": 256
}
}
},

CouchDB's Linked Documents in a View

I'm having a hard time getting my head around CouchDB's linked documents feature.
I have two types of data being stored in a single CouchDB database:
{
"id":"1",
"type": "track",
"title": "Bohemian Rhapsody"
}
{
"id":"2",
"type": "artist",
"name": "Queen",
"tracks": ["1"]
}
I'm under the impression that I can write a view like the one below and get the following documents emited:
{
"id":"2",
"type": "artist",
"name": "Queen",
"tracks": [
{
"id":"1",
"type": "track",
"title": "Bohemian Rhapsody"
}
]
}
I've been trying this view, but it's not working the way I'm expecting:
function(doc) {
if(doc.type == 'artist') {
var tracks = [];
for(var i = 0; i < doc.tracks.length; i++) {
tracks.push({_id:doc.tracks[i]});
}
newdoc = eval(uneval(doc));
newdoc.tracks = tracks;
emit(doc._id,newdoc);
}
}
example here: http://jphastings.iriscouch.com/_utils/database.html?music/_design/test/_view/linked
This isn't returning what I'd hope - do you have any suggestions? Thanks
Okay I finally understand what you are trying to do.Yes this is possible.Here is how.
You have 2 documents
{
"_id":"anyvalue",
"type": "track",
"title": "Bohemian Rhapsody"
}
{
"_id":"2",
"type": "artist",
"name": "Queen",
"tracks": ["anyvalue"]
}
What you were doing wrong was not having quotes around the value of tracks(the item in the array).
2)The reference id must be _id for this to work.The difference is worth noting since you can have id field but only _id are used to identify documents.
For the result you want this view would suffice
function(doc) {
if (doc.type === 'artist') {
for (var i in doc.tracks) {
var id = doc.tracks[i];
emit(id, { _id: id });
}
}
}
What you want to be doing is use an emit function inside the for loop to emit the id field of the 'track' of every artist.
Then you want to query couch db view with the include_docs=true parameter.Here is the final result for the database that you created on iris couch.
http://jphastings.iriscouch.com/music/_design/test/_view/nested?reduce=false&include_docs=true
{
"total_rows": 3,
"offset": 0,
"rows": [
{
"id": "0b86008d8490abf0b7e4f15f0c6a50a7",
"key": "0b86008d8490abf0b7e4f15f0c6a463b",
"value": {
"_id": "0b86008d8490abf0b7e4f15f0c6a463b"
},
"doc": {
"_id": "0b86008d8490abf0b7e4f15f0c6a463b",
"_rev": "3-7e4ba3bfedd29a07898125c09dd7262e",
"type": "track",
"title": "Boheniam Rhapsody"
}
},
{
"id": "0b86008d8490abf0b7e4f15f0c6a50a7",
"key": "0b86008d8490abf0b7e4f15f0c6a5ae2",
"value": {
"_id": "0b86008d8490abf0b7e4f15f0c6a5ae2"
},
"doc": {
"_id": "0b86008d8490abf0b7e4f15f0c6a5ae2",
"_rev": "2-b3989dd37ef4d8ed58516835900b549e",
"type": "track",
"title": "Another one bites the dust"
}
},
{
"id": "0b86008d8490abf0b7e4f15f0c6a695e",
"key": "0b86008d8490abf0b7e4f15f0c6a6353",
"value": {
"_id": "0b86008d8490abf0b7e4f15f0c6a6353"
},
"doc": {
"_id": "0b86008d8490abf0b7e4f15f0c6a6353",
"_rev": "2-0383f18c198b813943615d2bf59c212a",
"type": "track",
"title": "Stripper Vicar"
}
}
]
}
Jason explains it wonderfully in this post
Best way to do one-to-many "JOIN" in CouchDB
this link is also helpful for entity relationships in couch db
http://wiki.apache.org/couchdb/EntityRelationship

Resources