Spring data and ElasticSearch, how do I search by an entire object? - spring-boot

I have the following mapping
"mappings": {
"dynamic": "strict",
"properties": {
"_class": {
"type": "keyword"
},
"id": {
"type": "keyword"
},
...
"user": {
"properties": {
"username": {
"type": "keyword"
},
"userType": {
"type": "keyword"
}
}
},
...
My java object looks like this
class foo {
String id,
...
User user;
...
}
class User {
String username;
UserType userType; // this is enum
}
In my repository I am trying to find by
public List<Foo> findByUser(User user);
This will not return anything, I double and triple checked the data and mapping and the user object that I am passing. All looks good, but I won't get any results.
If I write a query like so, it does work:
{
"size": 100,
"query": {
"bool" : {
"must" : [
{
"term" : {
"user.username" : {
"value" : "user1"
}
}
},
{
"term" : {
"user.userType" : {
"value" : "ACTIVE"
}
}
}
]
}
}
}
What am I doing wrong?

Related

How to change mapping type on a very large ElasticSearch index?

I tried to this solution from here, but it didn't worked for me.
I needed to convert the nested text fields like one.second.third to ip type. So I added mapping like
PUT .the-index-2022.12.20-0000025/_mapping
{
"properties": {
"one": {
"type": "object",
"properties": {
"second": {
"type":"object",
"properties": {
"ip_address1": {
"type": "ip"
},
"ip_address2": {
"type": "ip"
}
}
}
}
}
}
}
Then I used
POST .the-index-2022.12.20-0000025/_update_by_query?wait_for_completion=false&slices=auto
It executed successfully but still didnt change the fields type to ip.
What can I do else or what is the problem here?
Thanks in advance
Also tried like:
PUT .the-index-2022.12.20-0000025/_mapping
{
"properties": {
"one": {
"properties": {
"second": {
"properties": {
"ip_address1": {
"type": "ip"
},
"ip_address2": {
"type": "ip"
}
}
}
}
}
}
}
Could you please help?
I've added 3 new fields in ip type:
{
".the-index-2022.12.20-0000025" : {
"mappings" : {
"one.sec.ip1" : {
"full_name" : "one.sec.ip1",
"mapping" : {
"ip1" : {
"type" : "ip"
}
}
},
"one.sec.ip2" : {
"full_name" : "one.sec.ip2",
"mapping" : {
"ip2" : {
"type" : "ip"
}
}
},
"one.sec.ip3" : {
"full_name" : "one.sec.ip3",
"mapping" : {
"ip3" : {
"type" : "ip"
}
}
}
}
}
}

Trying to update a nested geoip location field in elasticsearch

Here is what I've tried:
POST orders/_update_by_query
{
"script" : "ctx._source.geoip += newElement",
"params": {
"newElement": {
"location" : "[40.730610, -73.935242]"
}
},
"query": {
"term": {
"CITY": {
"value": "nyc"
}
}
}
}
The above throws error Unknown key for a START_OBJECT in [params].
Second Attempt:
POST orders/_update_by_query
{
"script":{
"source":
"for (item in ctx._source.geoip){item.location = '[40.730610, -73.935242]'}",
"lang":"painless"
},
"query": {
"term": {
"CITY": {
"value": "nyc"
}
}
}
}
The above throws null pointer exception, and points to the period at source.geoip
I also tried changing the value of location to just test but receive the same errors.
Here is my mapping:
{
"orders" : {
"mappings" : {
"properties" : {
"geoip" : {
"dynamic" : "true",
"properties" : {
"location" : {
"type" : "geo_point"
}
}
}
}
}
I am using ES v7.2 and Kibana v7.2
A couple of issues in the 1st approach:
params need to be defined within the script object, not below it
newElement needs to be accessed using params.newElement
you cannot append += params.newElement to a nonexistent ctx._source.geoip
you cannot append an object to a single-value field -- you can just assign it
location is of the geo_point type, so either [40.730610, -73.935242] ([lon, lat]) or "-73.935242,40.730610" ("lat,lon"), but not a mixture of both
Working command:
POST orders/_update_by_query
{
"script": {
"inline": "ctx._source.geoip = params.newElement",
"params": {
"newElement": {
"location": [
40.73061,
-73.935242
]
}
}
},
"query": {
"term": {
"CITY": {
"value": "nyc"
}
}
}
}

Is it impossible to index a document where a property has multiple fields, one of them being a completion type with contexts?

Here is my mapping (some fields renamed/removed), I'm using ES 6.0
{
"mappings": {
"_doc" :{
"properties" : {
"username" : {
"type": "keyword",
"fields": {
"suggest" : {
"type" : "completion",
"contexts": [
{
"name": "user_id",
"type": "category"
}
]
}
}
},
"user_id": {
"type": "integer"
}
}
}
}
}
Now when I try to index a document with
PUT usernames/_doc/1
{
"username" : "JOHN",
"user_id": 1
}
OR
PUT usernames/_doc/1
{
"username" : {
"input": "JOHN",
"contexts: {
"user_id": 1
}
}
"user_id": 1
}
The first doesn't index with context and the second just fails. I've attempted to add a path like so,
{
"mappings": {
"_doc" :{
"properties" : {
"username" : {
"type": "keyword",
"fields": {
"suggest" : {
"type" : "completion",
"contexts": [
{
"name": "user_id",
"type": "category",
"path": "user_id",
}
]
}
}
},
"user_id": {
"type": "integer"
}
}
}
}
}
And attempting indexing again
PUT usernames/_doc/1
{
"username" : "JOHN",
"user_id": 1
}
But it just throws a context must be a keyword or text error. Do I have to give up and make a totally new property username-autocomplete instead? Or is there some magical way where I can have a context completion suggester and another field on the same property, and be able to index like I would other multifield properties?
The second approach is the right one (i.e. with the path inside the context), but you need to set the user_id field as a keyword and it will work:
{
"mappings": {
"_doc" :{
"properties" : {
"username" : {
"type": "keyword",
"fields": {
"suggest" : {
"type" : "completion",
"contexts": [
{
"name": "user_id",
"type": "category",
"path": "user_id",
}
]
}
}
},
"user_id": {
"type": "keyword" <--- change this
}
}
}
}
}
Then you can index your document without creating an additional field, like this:
PUT usernames/_doc/1
{
"username" : "JOHN",
"user_id": "1" <--- wrap in double quotes
}

ElasticSearch nested query score

I have an index :
PUT my_index2
{
"mappings": {
"my_type": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
}
I have two documents:
POST my_index2/my_type/
{
"user": [
{
"name": "Alice Don"
},
{
"name": "Smith"
}
]
}
POST my_index2/my_type/
{
"user": [
{
"name": "Alice David"
}
]
}
When I search it:
GET my_index2/_search
{
"query": {
"nested" : {
"path" : "user",
"query" : {
"bool" : {
"should" : [
{ "match" : {"user.name" : "Alice"} }
]
}
}
}
}
}
Although both documents have one "Alice", the score of the first one is higher. How could that possible?
Your first document has shorter "name", so you got more same chars between "query" and "name"

How to exclude inherited object properties from mappings

I'm trying to setup a mapping for an object that looks like this:
class TestObject
{
public long TestID { get; set; }
[ElasticProperty(Type = FieldType.Object)]
public Dictionary<long, List<DateTime>> Items { get; set; }
}
I use the following mapping code (where Client is IElasticClient):
this.Client.Map<TestObject>(m => m.MapFromAttributes());
I get the following mapping result:
{
"mappings": {
"testobject": {
"properties": {
"items": {
"properties": {
"comparer": {
"type": "object"
},
"count": {
"type": "integer"
},
"item": {
"type": "date",
"format": "dateOptionalTime"
},
"keys": {
"properties": {
"count": {
"type": "integer"
}
}
},
"values": {
"properties": {
"count": {
"type": "integer"
}
}
}
}
},
"testID": {
"type": "long"
}
}
}
}
This becomes a problem when I want to do a search like this:
{
"query_string": {
"query": "[2015-06-03T00:00:00.000 TO 2015-06-05T23:59:59.999]",
"fields": [
"items.*"
]
}
}
This causes exceptions, that I guess are because of all the fields in the items object are not of the same type. What is the proper mapping to searches of this type?
I was able to fix this by using the following mapping:
this.Client.Map<TestObject>(m => m.MapFromAttributes())
.Properties(p => p
.Object<Dictionary<long, List<DateTime>>>(o => o.Name("items")));

Resources