elasticksearch nested query - elasticsearch

I have a index with some nested information and right now struggle with how make to make a query.
The index below represents a car piece and this piece belongs to 2 cars.
{
"_index": "items_production_20180411115923024",
"_type": "item",
"_id": "1232",
"_score": 21.715849,
"_source": {
"description": "CUBO RODA TRASEIRA VW:GOL, VOYAGE G5/G6 09> C/ABS",
"observation": null,
"brand_id": "1 ",
"product_line_id": "13",
"line_id": "1",
"line": "Rolamentos",
"segment_id": "21",
"segment": "cubo de roda",
"application_features": [
"4 furos"
],
"original_codes": [
" 5u0 501 611 "
],
"original_brands": [
"volkswagen"
],
"vehicles": [
{
"id": "285",
"brand": "volkswagen",
"name": "golf",
"years": [
"2009",
"2010",
"2011",
"2012",
"2013",
"2014",
"2015",
"2016",
"2017",
"2018"
]
},
{
"id": "345",
"brand": "volkswagen",
"name": "jetta",
"years": [
"2015",
"2016",
"2017",
"2018"
]
}
]
}
}
I have to make the query match to one single result when search for the model and year of a car. i.e.:
GET items_production_20180411115923024/_search
{
"query":{
"bool":{
"must":{
"multi_match":{
"query":"golf 2010",
"type":"cross_fields",
"operator":"and",
"fields":[
"vehicles.name^8",
"vehicles.years^8"
]
}
}
}
},
"size":10,"from":0
}
I have to return all docs which are pieces of a golf year 2010. But my response is none?
What am I doing wrong? How can I make this query?

I see you have a typo in the query. Replace vehicle_names^8 with vehicles.name^8.

Is vehicles.years an analyzed field? If not, it will not match against the term "golf 2010".
You might be able to use copy_to in your mapping to get terms from the name and the year in one field. Then you can do a simple query against that.

Related

Elastic/Kibana: support for plurals in query searches

I'll simplify my issue. Let's say I have an index with 3 documents I've created with Kibana:
PUT /test/vendors/1
{
"type": "doctor",
"name": "Phil",
"works_in": [
{
"place": "Chicago"
},
{
"place": "New York"
}
]
}
PUT /test/vendors/2
{
"type": "lawyer",
"name": "John",
"works_in": [
{
"place": "Chicago"
},
{
"place": "New Jersey"
}
]
}
PUT /test/vendors/3
{
"type": "doctor",
"name": "Jill",
"works_in": [
{
"place": "Chicago"
}
]
}
Now I'm running a search:
GET /test/_search
{
"query": {
"multi_match" : {
"query": "doctor in chicago",
"fields": [ "type", "place" ]
}
}
}
And I'm getting a good response:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0.2876821,
"hits": [
{
"_index": "test",
"_type": "vendors",
"_id": "1",
"_score": 0.2876821,
"_source": {
"type": "doctor",
"name": "Phil",
"works_in": [
{
"place": "Chicago"
},
{
"place": "New York"
}
]
}
},
{
"_index": "test",
"_type": "vendors",
"_id": "3",
"_score": 0.2876821,
"_source": {
"type": "doctor",
"name": "Jill",
"works_in": [
{
"place": "Chicago"
}
]
}
}
]
}
}
Now things begin to get problematic...
Changed the doctor to doctors
GET /test/_search
{
"query": {
"multi_match" : {
"query": "doctors in chicago",
"fields": [ "type", "place" ]
}
}
}
Zero results as doctors not found. Elastic doesn't know about plural vs. singular.
Change the query to New York
GET /test/_search
{
"query": {
"multi_match" : {
"query": "doctor in new york",
"fields": [ "type", "place" ]
}
}
}
But the response result set gives me the doctor in Chicago in addition to the doctor in New York. the fields are matched with OR...
Another interesting question is, what happens if someone usesdocs or physicians or health professionals but means doctor. IS there a provision where I can teach Elasticsearch to funnel those into "doctor"?
Is there any pattern, way around these using elasticsearch alone? where I won't have to analyze the string for meaning in my own application which will then construct a complex exact elasticsearch query to match it?
I would appreciate any pointer in the right direction
I'm assuming that the fields type and place are of Text type with Standard Analyzers.
To manage singular/plurals, what you are looking for is called Snowball Token Filter which you would need to add to the mapping.
Another requirement that you've mentioned saying for e.g. physicians should also be equated as doctor, you need to make use of Synonym Token Filter
Below is how your mapping should be. Note that I've just added analyzer to type. You can make similar changes to the mapping to the other fields.
Mapping
PUT <your_index_name>
{
"settings":{
"analysis":{
"analyzer":{
"my_analyzer":{
"tokenizer":"standard",
"filter":[
"lowercase",
"my_snow",
"my_synonym"
]
}
},
"filter":{
"my_snow":{
"type":"snowball",
"language":"English"
},
"my_synonym":{
"type":"synonym",
"synonyms":[
"docs, physicians, health professionals, doctor"
]
}
}
}
},
"mappings":{
"mydocs":{
"properties":{
"type":{
"type":"text",
"analyzer":"my_analyzer"
},
"place":{
"type":"text",
"analyzer":"my_analyzer"
}
}
}
}
}
Notice how I've added the synonyms in the mapping itself, instead of that I'd suggest you to have the synonyms added in text file like below
{
"type":"synonym",
"synonyms_path" : "analysis/synonym.txt"
}
According to the link I've shared, it mentions that the above configures a synonym filter, with a path of analysis/synonym.txt (relative to the config location).
Hope it helps!

How to perform a multi level logical query in elasticsearch

Let's say that we have such query
(a or b or c) and (x or y or z) and (f or g or h) ...
How we can perform such query using Elasticsearch?
I tried the bool query, but I still confused about must, should... clauses and how to place different conditions in these clauses to obtain a logical result
Here is a sample of my data(courses type):
[{
"_index": "training-hub",
"_type": "courses",
"_id": "58ad8090604aff26df131971",
"_score": 1,
"_source": {
"title": "Getting Started with Vue.js",
"description": "In this course, you will learn the basics of Vue.js framework and how to create amazing web applications using this framework",
"slug": "hzrthtrjhyjyt--by--Jemli-Fathi",
"format": [
"Intra-entreprise"
],
"duration": 6,
"language": "EN",
"requirements": [
"Basics of web development"
],
"tags": [],
"audience": [
"Web developers"
],
"price": 600,
"cover": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487840598/training-hub/k1h0tzciyjflqvtlyr2l.png",
"scheduleUrl": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487765627/training-hub/sozofm68nrwxhta3ga3u.png",
"trainer": {
"firstname": "Jemli",
"lastname": "Fathi",
"photo": "https://ucarecdn.com/5923a1bb-3e77-47d0-bd5b-7d07b0f559fe/16487460_1269388943138870_3235853817844339449_o.jpg"
},
"courseCategory": {
"name": "Game Development"
},
"createdAt": "2017-02-22T12:14:08.186Z",
"updatedAt": "2017-02-24T10:39:22.896Z"
}
},
{
"_index": "training-hub",
"_type": "courses",
"_id": "58ad81c0604aff26df131973",
"_score": 1,
"_source": {
"title": "Create your first Laravel application today!",
"description": "In this course, you're gonna learn how create fancy web applications using Laravel PHP Framework ...",
"slug": "sdvrehtrthrth--by--Jemli-Fathi",
"format": [
"Intra-entreprise",
"Inter-entreprise"
],
"duration": 6,
"language": "EN",
"requirements": [
"Basics of Web development",
"Basics of PHP language"
],
"tags": [],
"audience": [
"Web developers",
"PHP developers"
],
"price": 600,
"cover": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487841464/training-hub/dpgqbchualnfc78n69gs.png",
"scheduleUrl": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487765627/training-hub/sozofm68nrwxhta3ga3u.png",
"trainer": {
"firstname": "Jemli",
"lastname": "Fathi",
"photo": "https://ucarecdn.com/5923a1bb-3e77-47d0-bd5b-7d07b0f559fe/16487460_1269388943138870_3235853817844339449_o.jpg"
},
"courseCategory": {
"name": "Web Development"
},
"createdAt": "2017-02-22T12:19:12.376Z",
"updatedAt": "2017-02-23T09:39:23.414Z"
}
},
{
"_index": "training-hub",
"_type": "courses",
"_id": "58aead4faecfc31e4559d49b",
"_score": 1,
"_source": {
"title": "Getting Started with Docker",
"description": "After taking this course, you will be able to use Docker in real life projects and you can bootstrap your projects into different containers",
"slug": "regrehgreh--by--Jemli-Fathi",
"format": [
"Intra-entreprise"
],
"duration": 5,
"language": "EN",
"requirements": [
"Basic Linux Shell skills",
"Basic knowledge of Linux environment"
],
"tags": [],
"audience": [
"Dev-Ops",
"Web Developers"
],
"price": 999,
"cover": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487939101/training-hub/vkqupkiqerq0kgjgd0km.png",
"scheduleUrl": "http://res.cloudinary.com/dqihnnzaj/image/upload/v1487842509/training-hub/r9y1qisyfelseeuzgtt3.png",
"trainer": {
"firstname": "Jemli",
"lastname": "Fathi",
"photo": "https://ucarecdn.com/5acb1b5f-b550-4560-b085-2d75384e5ec8/13567067_1064268623650904_3773193220506255422_n.jpg"
},
"courseCategory": {
"name": "Web Development"
},
"createdAt": "2017-02-23T09:37:19.758Z",
"updatedAt": "2017-02-24T12:31:32.078Z"
}
}]
What I need exactly is to filter courses like this:
(category1 or category2 ...) and (format1 or format2...) and
(language1 or language2)...
You may use bool queries combined with the terms query for the desired behavior
GET _search
{
"query" : {
"bool": {
"must": [ //AND
{
"terms": {
"category.name": [ // Category with value VALUE1 or VALUE2
"VALUE1",
"VALUE2"
]
}
},
{
"terms": {
"format": [// format with value FORMAT1 or FORMAT2
"FORMAT1",
"FORMAT2"
]
}
},
{
"terms": {
"language": [// language with value LANG1 or LANG2
"LANG1",
"LANG2"
]
}
}
]
}
}
}
Also, please make sure that the fields that are used for term matching, are not_analyzed.
Please read up on mappings starting here: http://www.elasticsearch.org/guide/reference/mapping/.
Elasticsearch Query String Query does the same what you are looking for.
Look at following code snippet extracted from official docs here
GET /_search
{
"query": {
"query_string": {
"query": "(content:this OR name:this) AND (content:that OR name:that)"
}
}
}
Hope this helps!

Elasticsearch query on inner list and get only matching objects from list instead of entire list in result document

In following elastic search documents need to find comments from specific name eg "Mary Brown". Basically query on inner list and get only matching objects from list instead of entire list in result document. Is it possible. I have defined nested as mapping for 'comments'
{
"title": "Investment secrets",
"body": "What they don't tell you ...",
"tags": [ "shares", "equities" ],
"comments": [
{
"name": "Mary Brown",
"comment": "Lies, lies, lies",
"age": 42,
"stars": 1,
"date": "2014-10-18"
},
{
"name": "John Smith",
"comment": "You're making it up!",
"age": 28,
"stars": 2,
"date": "2014-10-16"
},
{
"name": "Mary Brown",
"comment": "making it!!!",
"age": 42,
"stars": 3,
"date": "2014-10-20"
}
]
}
Since you have properly mapped your comments field as nested, then yes this is possible using inner_hits, like this:
{
"_source": false,
"query": {
"nested": {
"path": "comments",
"inner_hits": { <---- use inner_hits here
"_source": [
"comment", "date"
]
},
"query": {
"bool": {
"must": [
{
"term": {
"comments.name": "Mary Brown"
}
}
]
}
}
}
}
}

Elastic search range query

Consider 2 documents in an index as like below:
{
"_index": "32",
"_type": "places",
"_id": "_FqlAzzSRN6Ge_294D5Mwg",
"_score": 1,
"_source": {
"name_3": "xxxx",
"id_3": "xxxxx",
"name_2": "xxxx",
"id_2": "xxx",
"name_1": "xxx",
"id_1": "xxx",
"tempid": "xxxxx",
"field1": 316.6666666666667,
"type": "processeddata"
}
},
{
"_index": "32",
"_type": "places",
"_id": "3RCO-zHeSr2nWFZd8W-MDg",
"_score": 1,
"_source": {
"name_3": "yyyy",
"id_3": "yyy",
"name_2": "yyy",
"id_2": "yyy",
"name_1": "yyyy",
"id_1": "yyy",
"tempid": "yy",
"field2": 400.6666666666667,
"type": "processeddata"
}
}
I want to construct a query for the following scenario. I have to find the documents for field in particular range.
field1:200-400
field2:300-400 so the above 2 documents should come.
My query is as follows:
"query": {
"bool": {
"must": [
{
"range": {
"field1": {
"gte": 200,
"lte": 400
}
},"range": {
"field2": {
"gte": 300,
"lte": 400
}
}
}
]
}
}
But the above query "Looks for 2 fields in a singe document, so no result is coming. SO i have to make to search if any of the filed satisfies the range in the document should return. Please share your ideas. Thanks in advance.
You need to use bool should and not bool must. That would mean match any document that matches at least one condition.
NOTE: Your second condition won't match second document as 400.66 does not fall in the range [300, 400].

How to search exact text in nested document in elasticsearch

I have a index like this,
"_index": "test",
"_type": "products",
"_id": "URpYIFBAQRiPPu1BFOZiQg",
"_score": null,
"_source": {
"currency": null,
"colors": [],
"api": 1,
"sku": 9999227900050002,
"category_path": [
{
"id": "cat00000",
"name": "B1"
},
{
"id": "abcat0400000",
"name": "Cameras & Camcorders"
},
{
"id": "abcat0401000",
"name": "Digital Cameras"
},
{
"id": "abcat0401005",
"name": "Digital SLR Cameras"
},
{
"id": "pcmcat180400050006",
"name": "DSLR Package Deals"
}
],
"price": 1034.99,
"status": 1,
"description": null,
}
And i want to search only exact text ["Camcorders"] in category_path field.
I did some match query, but it search all the products which has "Camcorders" as a part of the text. Can some one help me to solve this.
Thanks
To search in nested field use like following query
{
"query": {
"term": {
"category_path.name": {
"value": "b1"
}
}
}
}
HOpe it helps..!
you could add one more nested field raw_name with not_analyzed analyzer and match against it.

Resources