i'm using elasticsearch-rails for a project, there is a combine search feature, all columns are in one table. I just write a custom search function, and the search dsl didn't work, can't have any results.
def self.combine_search_filter(remark=nil, sim_card_supplier_id=nil, work_mode=nil, operator_status=nil, platform_management_status=nil, online_status=nil, sim_card_set_id=nil, iccid_from=nil, iccid_to=nil, actived_at_from=nil, actived_at_to=nil, check_in_at_from=nil, check_in_at_to=nil, device_mac_from=nil, device_mac_to=nil)
response = __elasticsearch__.search(
"size": 1000,
"query": {
"filtered": {
"filter": {
"bool": {
"filter": [
{ "term": { "sim_card_supplier_id": sim_card_supplier_id } },
{ "term": { "work_mode": work_mode } },
{ "term": { "operator_status": operator_status } },
{ "term": { "platform_management_status": platform_management_status } },
{ "term": { "online_status": online_status } },
{ "term": { "sim_card_set_id": sim_card_supplier_id } }
{ "range": { "iccid": { "from": iccid_from, "to": iccid_to }}},
{ "range": { "check_in_at": { "from": check_in_at_from, "to": check_in_at_to }}},
{ "range": { "actived_at": { "from": actived_at_from, "to": actived_at_to }}},
{ "range": { "device_mac": { "from": device_mac_from, "to": device_mac_to }}}
]
}
}
}
}
)
end
and the params maybe pass nil, how can i do that make the search dsl valid?
I would rather suggest you to use searchkick gem for rails which makes elastic search as simple as that and makes your search more intelligent and queries simple.
My bad, i just figure this out, ruby keyword function should be like this:
def self.combine_search_filter(options = {})
response = __elasticsearch__.search(
"size": 1000,
"query": {
"filtered": {
"filter": {
"bool": {
"filter": [
{ "term": { "sim_card_supplier_id": 104 } },
{ "term": { "work_mode": options[:work_mode] } },
{ "term": { "operator_status": options[:operator_status] } },
{ "term": { "platform_management_status": options[:platform_management_status] } },
{ "term": { "online_status": options[:online_status] } },
{ "term": { "sim_card_set_id": 76 } },
{ "range": { "iccid": { "from": options[:iccid_from], "to": options[:iccid_to] }}},
{ "range": { "check_in_at": { "from": options[:check_in_at_from], "to": options[:check_in_at_to] }}},
{ "range": { "actived_at": { "from": options[:actived_at_from], "to": options[:actived_at_to] }}},
{ "range": { "device_mac": { "from": options[:device_mac_from], "to": options[:device_mac_to] }}}
]
}
}
}
}
)
end
this search will have the correct result. The options[:key] may be nil will cause the wrong result, so i'm gonna delete the nil key of the dsl hash, then pass it to search()
Related
I am learning ES and I am having problems with this query:
Given 2 products:
products/_source/1
{
"product_id": "58410-2",
"name": [
{
"locale": "en",
"translation": "CBC panel"
},
{
"locale": "vn",
"translation": "CBC panel VN"
}
],
"status": "active",
"category": {
"id": 8,
"name": [
{
"locale": "en",
"translation": "Hematology"
},
{
"locale": "vn",
"translation": "huyết học"
}
]
},
"children": [
{
"product_id": "6690-2",
"name": [
{
"locale": "en",
"translation": "Leukocytes"
},
{
"locale": "vn",
"translation": "Leukocytes vn"
}
],
"status": "active",
"category": {
"id": 8,
"name": [
{
"locale": "en",
"translation": "Hematology"
},
{
"locale": "vn",
"translation": "huyết học"
}
]
},
"children": []
}]}
and
products/_source/2
{
"product_id": "6690-2",
"name": [
{
"locale": "en",
"translation": "Leukocytes"
},
{
"locale": "vn",
"translation": "Leukocytes vn"
}
],
"status": "active",
"category": {
"id": 8,
"name": [
{
"locale": "en",
"translation": "Hematology"
},
{
"locale": "vn",
"translation": "huyết học"
}
]
},
"children": []
}
where a product is a single document but also can be nested in a children array of other products. Both products are different documents in the index.
and this index:
{
"products": {
"aliases": {},
"mappings": {
"dynamic": "false",
"properties": {
"category": {
"properties": {
"name": {
"properties": {
"locale": {
"type": "keyword"
},
"translation": {
"type": "text"
}
}
}
}
},
"children": {
"type": "nested"
},
"name": {
"properties": {
"locale": {
"type": "keyword"
},
"translation": {
"type": "text"
}
}
},
"product_id": {
"type": "keyword"
},
"status": {
"type": "keyword"
}
}
},
"settings": {
"index": {
"routing": {
"allocation": {
"include": {
"_tier_preference": "data_content"
}
}
},
"number_of_shards": "3",
"provided_name": "products",
"number_of_replicas": "1"
}
}
}
}
I want to be able to query for "Leuko" (or the category or the product_id) and retrieve both products, the single product and the root product.
I have tried using object field, nested, flattened but I think the problem is I don't know how to properly write the query, I have tried things like this (I am using a ruby library but I think it is easy to follow):
#query = {
query: {
query_string: {
fields: ['name.translation', 'children.name.translation', 'category.name.translation', 'children.product_id'],
query: "*#{text}*"
}
},
size: 50
}
#query = {
query: {
nested: {
path: 'children',
query: {
bool: {
should: [
term: { 'children.name.translation' => "*#{text}*" },
term: { 'name.translation' => "*#{text}*" }
]
}
}
}
}
}
but I think at some point I dunno what I am doing anymore and I am just randomly trying different stuff from the documentation.
Follow my query suggestion. Note that I had to add the fields in the Nested object to the mapping.
Mapping:
{
"mappings": {
"dynamic": "false",
"properties": {
"category": {
"properties": {
"name": {
"properties": {
"locale": {
"type": "keyword"
},
"translation": {
"type": "text"
}
}
}
}
},
"children": {
"type": "nested",
"properties": {
"product_id": {
"type": "keyword"
},
"category": {
"properties": {
"name": {
"properties": {
"locale": {
"type": "keyword"
},
"translation": {
"type": "text"
}
}
}
}
},
"name": {
"properties": {
"locale": {
"type": "keyword"
},
"translation": {
"type": "text"
}
}
},
"status": {
"type": "keyword"
}
}
},
"name": {
"properties": {
"locale": {
"type": "keyword"
},
"translation": {
"type": "text"
}
}
},
"product_id": {
"type": "keyword"
},
"status": {
"type": "keyword"
}
}
}
}
Query:
{
"query": {
"bool": {
"minimum_should_match": 1,
"should": [
{
"nested": {
"path": "children",
"query": {
"wildcard": {
"children.name.translation": "leuko*"
}
}
}
},
{
"wildcard": {
"name.translation": "leuko*"
}
}
]
}
}
}
hint
See that you use translation. Avoid using array to make your queries simpler.
What I would do in your case is to create a field for each language, this makes the use of analyzer more flexible for each type of language and you stop using an array and work with an object.
PUT test
{
"mappings": {
"properties": {
"name":{
"type": "text",
"fields": {
"es":{
"type": "text",
"analyzer":"english"
},
"vn":{
"type": "text"
}
}
}
}
}
}
POST test/_doc/
{
"name": "Leukocytes"
}
An example query using field languages.
GET test/_search
{
"query": {
"multi_match": {
"query": "Leukocytes",
"fields": ["name.es", "name.vn"]
}
}
}
I'm trying to boost up the query using elastic search. Headlines that are published recently must be boosted up and should come on top. However, I have return the following code:
{
"query": {
"function_score": {
"query": {
"bool": {
"must": {
"match": {
"keywords": {
"query":"trump"
}
}
},
"should": [
{ "match": {
"type": {
"query": "headline"
}
}}
]}},
"functions": [
{ "boost": 5 },
{
"gauss": {
"versioncreated": {
"origin": "now/d",
"scale": "50w",
"offset": "4w",
"decay": "0.5"
}}}],
"score_mode": "sum"
}
}}
I'm getting this error :-
{
"error": {
"root_cause": [
{
"type": "parsing_exception",
"reason": "no [score_function] registered for [params]",
"line": 24,
"col": 20
}
],
"type": "parsing_exception",
"reason": "no [score_function] registered for [params]",
"line": 24,
"col": 20
},
"status": 400
}
You query is a bit wrong. What do you want do by this?
"functions": [
{ "boost": 5 },
If you want to boost it try to use this query
{
"query": {
"function_score": {
"query": {
"bool": {
"must": {
"match": {
"keywords": {
"query": "trump"
}
}
},
"should": [
{
"match": {
"type": {
"query": "headline"
}
}
}
]
}
},
"functions": [
{
"gauss": {
"versioncreated": {
"origin": "now/d",
"scale": "50w",
"offset": "4w",
"decay": "0.5"
}
}
}
],
"boost": 5,
"score_mode": "sum"
}
}
}
Im trying to search only on the following fields:
name (product name)
vendor.username
vendor.name
categories_name
But the results is to wide, I want the results to be exactly what user is typed.
Example:
I type Cloth A I want the result to be exactly Cloth A not something else contain Cloth or A
Here is my attempt:
```
GET /products/_search
{
"query": {
"filtered": {
"query": {
"multi_match": {
"query": "cloth A",
"fields": [
"name",
"vendor.name",
"vendor.username",
"categories_name"
]
}
},
"filter": [
{
"term": {
"is_available": true
}
},
{
"term": {
"is_ready": true
}
},
{
"missing": {
"field": "deleted_at"
}
}
]
}
}
}
```
How do I do that? Thanks in advance
Put this in your multi_match
"multi_match": {
"type": "best_fields"
}
This one works:
"multi_match": {
"type": "phrase"
}
I'm migrating my elasticsearch from using facets to using aggregations, and I want to create a query where the aggregations represent all the creator names that begin with a certain letter.
I've created a nested index like so:
indexes creators, type: 'nested' do
indexes :name, type: 'string', analyzer: 'caseinsensitive', index: 'not_analyzed'
end
The following query will return all the items where a creator's name begins with a "b". Great working so far.
{
"query": {
"filtered": {
"query": {"match_all": {}},
"filter": {
"nested": {
"path": "creators",
"query": {
"prefix": {
"creators.name": {
"value": "b"
}
}
}
}
}
}
},
"aggregations": {
"creators": {
"nested": {
"path": "creators"
},
"aggs": {
"name": {
"terms": {
"field": "creators.name",
"size": 100
}
}
}
}
}
}
However, the aggregations part of the query returns ALL of the aggregations for the results, including instances creator names that do not begin with a "b." For instance, if I had an item with two creators:
"creators": [
{
"name": "Beyonce"
},
{
"name": "JayZ"
}
],
The aggregation results would include both JayZ and Beyonce. Like most people, I only want Beyonce.
Try this query and see how it goes:
{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"nested": {
"path": "creators",
"query": {
"prefix": {
"creators.name": {
"value": "b"
}
}
}
}
}
}
},
"aggregations": {
"creators": {
"nested": {
"path": "creators"
},
"aggs": {
"NAME": {
"filter": {
"prefix": {
"creators.name": "b"
}
},
"aggs": {
"name": {
"terms": {
"field": "creators.name",
"size": 100
}
}
}
}
}
}
}
}
I have this scenario wherein there are two multi_match searches within the same query. The trouble is, when I create the JSON for it in ruby, a json with non-unique keys doesn't seem possible so only one of them appear.
Here is my query:
{
"fields": ["id", "title",
"address.city", "address.state", "address.country", "address.state_code", "address.country_code", "proxy_titles", "location"],
"size":2,
"query":{
"filtered":{
"filter": {
"range": {
"custom_score": {
"gte": 100
}
}
},
"query":{
"bool": {
"must": {
"multi_match":{
"query": "term 1",
"type": "cross_fields",
"fields": ["title^2", "proxy_titles^2","description"]
}
},
"must": {
"multi_match": {
"query": "us",
"fields": ["address.city", "address.country", "address.state",
"address.zone", "address.country_code", "address.state_code", "address.zone_code"]
}
}
}
}
}
},
"sort": {
"_score": { "order": "desc" },
"variation": {"order": "asc"},
"updated_at": { "order": "desc" }
}
}
I have also only recently started using elasticsearch so it be very helpful if you could suggest me a better query to accomplish the same as well.
You have the syntax wrong. For multiple "must" values in a "bool", they need to be in an array. The documentation is not always terribly helpful, unfortunately (the bool query page shows this for "should" but not "must").
Try this:
{
"fields": ["id","title","address.city","address.state","address.country","address.state_code","address.country_code","proxy_titles","location"],
"size": 2,
"query": {
"filtered": {
"filter": {
"range": {
"custom_score": {
"gte": 100
}
}
},
"query": {
"bool": [
{
"must": {
"multi_match": {
"query": "term 1",
"type": "cross_fields",
"fields": ["title^2","proxy_titles^2","description"]
}
}
},
{
"must": {
"multi_match": {
"query": "us",
"fields": ["address.city","address.country","address.state","address.zone","address.country_code","address.state_code","address.zone_code"]
}
}
}
]
}
}
},
"sort": {
"_score": {
"order": "desc"
},
"variation": {
"order": "asc"
},
"updated_at": {
"order": "desc"
}
}
}