Searching term in subdocuments with elasticsearch - search

I have a index document structure like below;
{
"term":"some term",
"inlang":"some lang"
"translations" : {
{
"translation":"some translation",
"outlang":"some lang",
"translations" : {
{
"translation":"some translation 1"
"outlang": "some lang 1"
"translations" : {...}
}
}
},
...
}
}
I want to find a translation in such documents. However, this translation can exists at any level of this document. Is it possible to search term dynamically by using elasticsearch?
For example,
{
"query": {
"*.translation":"searchterm"
}
}
Thanks in advance

I have managed to do that with following query;
{
"query": {
"query_string": {
"query": "someterm",
"fields": ["*.translation"]
}
}
}
or
{
"query": {
"multi_match": {
"query": "someterm",
"fields": ["*.translation"]
}
}
}
You can see elasticsearch google group conversation here

No, I do not believe this functionality is built into ElasticSearch at the moment. This answer suggests you could build the functionality with a script, but it would be super slow.
In general, ES doesn't play nicely with nested data. It supports nested fields, but many of the more advanced search functionality isn't capable of operating on complex nested data. My suggestion is to denormalize your data so that every translation is represented by a single item in the index, and link between them with ID numbers.

Related

How do I search for the value "city"?

I'm trying to query through a somewhat simple collection with the following structure:
{
"name":[
{
"something":"",
"somethingelse":[
{
"name":"John",
"city":"NY"
}
]}]}
I have tried to search the value "city" with the dot notation but no success.
by reading this mongoDB doc, I see that to access array nested document you need to specify the index of the element instead of using ".".
For example with this object:
{
"name":"bob",
"info":[
{"birth":"10/01/1986"},
{"eyeColor":"blue"},
{"salary":2000}
]
}
I want to access the "birth" property, I will do something like this:
db.inventory.find({'info.0':"birth"})
Hope this help.
You can call the data and store it in an object say ob
ob= {
"name":[
{
"something":"",
"somethingelse":[
{
"name":"John",
"city":"NY"
}
]}]}
now you can do ob["name"][0]["somethingelse"][0]["city"]

elastic search exact phrase matching

I am new to ES. I am having trouble finding exact phrase matches.
Let's assume my index has a field called movie_name.
Let's assume I have 3 documents with the following values
movie_name = Mad Max
movie_name = mad max
movie_name = mad max 3d
If my search query is Mad Max, I want the first 2 documents to be returned but not the 3rd.
If I do the "not_analyzed" solution I will get only document 1 but not 2.
What am I missing?
I was able to do it using the following commands, basically create a custom analyzer, use the keyword tokenizer to prevent tokenization. Then use the analyzer in the "mappings" for the desired field, in this case "movie_name".
PUT /movie
{
"settings":{
"index":{
"analysis":{
"analyzer":{
"keylower":{
"tokenizer":"keyword",
"filter":"lowercase"
}
}
}
}
},
"mappings" : {
"search" : {
"properties" : {
"movie_name" : { "type" : "string", "analyzer":"keylower" }
}
}
}
}
Use Phrase matching like this :
{
"query": {
"match_phrase": {
"movie_name": "a"
}
}
}

How to filter out fields that do not exist in elastic search?

I would like to check if a field exists, and return results for documents where it does not exist. I am using the Golang library Elastic: https://github.com/olivere/elastic
I tried the following but it does not work:
e := elastic.NewExistsFilter("my_tag")
n := elastic.NewNotFilter(e)
filters = append(filters, n)
Ok, I wont go deep in your language query API. Since you want to search on a field not existing (null), use an exists filter inside a must_not (if you use bool filters):
{
"query": {
"filtered": {
"filter": {
"bool": {
"must_not": [
{
"exists": {
"field": "your_field"
}
}
]
}
}
}
},
"from": 0,
"size": 500
}
Hope this helps!
Thanks
You can use exist query with bool query must_not:
GET /_search
{
"query": {
"bool": {
"must_not": {
"exists": {
"field": "your_field"
}
}
}
}
}
Tested in Elasticsearch 6.5
You can create a bool query for not exists like this:
existsQuery := elastic.NewExistsQuery(fieldName)
existsBoolQuery := elastic.NewBoolQuery().MustNot(existsQuery)
I won't try to provide a complete solution, being that I'm not really familiar with the library your using (or, indeed, the go language).
However, Lucene doesn't support pure negative querying as you have here. Lucene needs to be told what to match. Negations like this serve strictly to prohibit search results, but do not implicitly match everything else.
In order to do what you are looking for, you would want to use a boolean query to combine your not filter with a match all (which I see is available in the library).
Note: As with anytime you use a match all, performance may suffer.

Elastic search having "not_analyzed" and "analyzed" together

I'm new to elasticsearch. What my business needs is that I should also do a partial matching on searchable fields I ended up with wildcard queries. my query is like this :
{
"query" : {
"wildcard" : "*search_text_here*"
}
}
Suppose that I'm searching for Red Flowers before the above query I was using an analyzed match query which provided me with both results for Red and Flowers lonely. but now my query only works when both Red Flowers are present together.
Use match phrase query as shown below for more information refer the ES doc:
GET /my_index/my_type/_search
{
"query": {
"match_phrase": {
"title": "red floewers"
}
}
}

$addToSet and return all new items added?

Is it possible to $addToSet and determine which items were added to the set?
i.e. $addToSet tags to a post and return which ones were actually added
Not really, and not with a single statement. The closest you can get is with the findAndModify() method, and compare the orginal document form to the fields that you submitted in your $addToSet statement:
So considering an initial document:
{
"fields": [ "B", "C" ]
}
And then processing this code:
var setInfo = [ "A", "B" ];
var matched = [];
var doc = db.collection.findAndModify(
{ "_id": "myid" },
{
"$addToSet": { "fields": { "$each": setInfo } }
}
);
doc.fields.forEach(function(field) {
if ( setInfo.indexOf(field) != -1 ) {
matched.push(field);
}
});
return matched;
So that is a basic JavaScript abstraction of the methods and not actually nodejs general syntax for either the native node driver or the Mongoose syntax, but it does describe the basic premise.
So as long as you are using a "default" implementation method that returns the "original" state of the document before it was modified the you can play "spot the difference" as it were, and as is shown in the code example.
But doing this over general "update" operations is just not possible, as they are designed to possibly affect one or more objects and never return this detail.

Resources