How to add preference to mutliple fields in elastic search query? - javascript

I have the following data:
makeStr: xerox
modelStr: Designjet 1050C
I want it to match
xerox
Designjet 1050C Plus Printer
but it is matching
canon
DesignJet 1050C
and currently I have this query
"query": {
"bool": {
"should":
{
"multi_match": {
"query": modelStr,
"type": "most_fields",
"fields": ['model.alphanum']
}
}
,
"filter": [
{
"match": {
"make.blur": makeStr
}
},
{
"match": {
"model.blur": modelStr
}
}
]
}
},
"functions": [{
"field_value_factor": {
"field": "isMpsSupported",
"factor": 1,
"missing": 0
}
}],
"boost_mode": "sum"
}
How do I give preference for makeStr such that it considers both makeStr and modelStr during search.

More preference can be given by using boost. Refer here
Something like makeStr^2 should work.

Related

how to fetch items if any search keyword matched?

I have this document in my elastic DB.I am using this package
https://www.npmjs.com/package/#elastic/elasticsearch
I am searching on title.
I am doing like this.
const result= await client.search({
index: 'products',
"query": {
"bool": {
"should": [
{
"wildcard": { "title": "*" + search + "*" }
}
],
"minimum_should_match": 1
}
}
when I search "title" this issue . it give me one result but When I am seacrhing i have issue . it is giving zero or 0 result.why ? is it possible to fetch that data.issue keyword is present in first collection why it is not picking ?
[
{
"_index": "products",
"_id": "wZRh3n8Bs9qQzO6fvTTS",
"_score": 1.0,
"_source": {
"title": "laptop issues",
"description": "laptop have issue present in according"
}
},
{
"_index": "products",
"_id": "wpRh3n8Bs9qQzO6fvzQM",
"_score": 1.0,
"_source": {
"title": "buy mobile",
"description": "mobile is in Rs 250"
}
},
{
"_index": "products",
"_id": "w5Rh3n8Bs9qQzO6fvzTz",
"_score": 1.0,
"_source": {
"title": "laptop payment",
"description": "laptop payment is given in any way"
}
}
]
how to search on keywords? any keyword match . I need to pick that whole colloection
If you want to match only some of the word from query then you can use match query with operator set to or.
{
"query": {
"match": {
"title": {
"query": "i have issues",
"operator": "or"
}
}
}
}
Update
To run the query which you mentioned in comment, You can use match_bool_prefix query.
{
"query": {
"match_bool_prefix": {
"title": {
"query": "i have issu"
}
}
}
}

Exact search with ElasticSearch 7.x

I am trying to find an exact search for an url with ElasticSearch ("#elastic/elasticsearch": "^7.5.0").
I have configured my mapping like so:
const schema = {
userId: {
type: "keyword"
},
url: {
type: "keyword",
index: false,
analyzer: 'keyword'
},
pageTitle: {
type: 'text',
},
pageText: {
type: 'text',
}
};
await client.indices.putMapping({
index,
type,
include_type_name: true,
body: {
properties: schema
}
})
I have tried different queries, and they looks like this:
body: {
query: {
bool: {
must: {
match: {
query: 'test stack',
analyzer: 'keyword',
}
}
}
}
}
Or second attempt:
body: {
query: {
constant_score: {
filter: {
bool: {
must: {
term: {
url: 'test stack'
}
}
}
}
},
}
}
None of them work. I want to get only the results where the exact string 'test/stack' is found. Any help would be highly appreciated.
Example of data I'm trying to add:
[
{"url": "test stack",
"userId": "anotherTest",
"pageTitle": "not important",
"pageText": "not important",
"log": [1, 3, 7]
},
{"url": "test stack",
"userId": "anotherTest",
"pageTitle": "not important",
"pageText": "not important",
"log": [1, 3, 7]
},
{"url": "test stack",
"userId": "anotherTest",
"pageTitle": "not important",
"pageText": "not important",
"log": [1, 3, 7]
}
]
Thanks.
I managed to make this work. Steps are:
1. Delete the index.
2. Delete the custom mapping function.
3. Create the index (with client.indices.create)
4. Index the first item (with client.index).
5. At this point, you can check in postman the dynamic mappings created by ElasticSearch (only visible after 1st item is indexed, by what I could tell). You can make a get request at http://localhost:9200/history/_mappings, and the response should look something like this:
{
"history": {
"mappings": {
"properties": {
"fullTitle": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"log": {
"properties": {
"startTime": {
"type": "long"
},
"timeSpent": {
"type": "long"
}
}
},
"protocol": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"text": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"totalTimeSpent": {
"type": "long"
},
"totalVisits": {
"type": "long"
},
"url": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"userId": {
"type": "long"
}
}
}
}
}
As you can see, any field indexed as text has attached another field, called keyword, which can be used for exact matches.
6. The query to get the exact matches looks like this:
const result = await esClient.search({
index: 'history',
body: {
query: {
term: {
'url.keyword': {
value: toInsert.url
}
}
}
}
})
At this point you should receive results only in case of exact match for the field "url" in my case. Hope this helps somebody else. Thanks #ibexit for trying to help me.
I see two problems:
The mapping defined for the url field says
url: {
type: "keyword",
index: false,
analyzer: 'keyword'
},
If you define index: false, the field will not be searchable at all. Using the following mapping should work properly:
url: {
type: "keyword"
}
See https://www.elastic.co/guide/en/elasticsearch/reference/current/keyword.html for more detailed information
The keyword mapped fields will not match using the match query which is designed to query text fields. Please use the term query instead for keyword fields. Please notice the example below using the Elasticseaech Query API:
GET /_search
{
"query": {
"term": {
"url": { <<= the field to search
"value": "test stack" <<= the searched value
}
}
}
}
Here is the according documentation: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-term-query.html
BTW: keep in mind that you need to reindex the data after a mapping change

Alphabetical sort using elasticsearch

I wounder if there any way or setting to perform an alphabetical sort in elasticsearch. I've got a field and I want to perform sort in descending order over it. Elastic performs it lexicographically. What I get:
Company name
Customer name
company address
What I want to get:
Company name
company address
Customer name
I found that I can create a custom analyser, but maybe there can be a better option?
use multifields to index the text field as lowercased keyword with fielddata true where you can sort.
{
"settings": {
"analysis": {
"analyzer": {
"keyword_lowercase": {
"tokenizer": "keyword",
"filter": ["lowercase"]
}
}
}
},
"mappings": {
"my_type": {
"properties": {
"text": {
"type": "text",
"fields": {
"raw": {
"type": "text",
"analyzer": "keyword_lowercase",
"fielddata": true
}
}
}
}
}
}
}
Query
{
"sort": [
{
"text.raw": {
"order": "asc"
}
}
]
}

Best way to filter if a field present in nested object in elasticsearch exists?

I have 1,000,000 contacts which are from different groups. For example
{"gps_id": [{"gid": "G1"},{"gid": "G2"}],"is_active": true,"contact": "c1"}
{"gps_id": [{"gid": "G2"}],"is_active": true,"contact": "c2"}
....
{"gps_id": [{"gid": "G1"},{"gid": "G2"}],"is_active": true,"contact": "c1000000"}
Consider G1 has 500,000 contacts, G2 has 1,000,000 contacts out of it 500,000 contacts which are already present in G1.
I want to filter above document object based on the condition,
"fetch unique contact from all respective group by group id".
I tried Elastic script query as below. But it doesn't work:
{
"query": {
"bool": {
"must" : {
"script" : {
"script" : {
"inline": "for (int i = 0; i < params.gps_id.length; ++i) {ctx._source.gps_id.add(params.gps_id[i]) }",
"lang": "painless",
"params": {
"gps_id": [
{
"gid": "G1"
},
{
"gid": "G2"
}
]
}
}
}
},
"must": [
{
"match": {
"is_active": true
}
},
{
"nested": {
"path": "gps_id",
"query": {
"bool": {
"must": [
{
"match": {
"gps_id.gid": "G1"
}
}
]
}
}
}
}
]
}
}
}
Here Group and its contact may increase in size.
Please suggest best way to implement it using Elasticsearch -5.1.2

Elasticsearch search with multi fields

How can i create body for elasticsearch like this
select * from table where full_name like '%q%' or address like '%q%' or description like '%q%' order by full_name , description , address
A wildcard query can be very expensive, especially if you search in several fields. The right way to do this is by using an nGram token filter on the fields you want to search only a part of.
First you create an index like below with a custom analyzer that will slice and dice your fields into searchable tokens:
curl -XPUT localhost:9200/tests -d '{
"settings": {
"analysis": {
"analyzer": {
"substring_analyzer": {
"tokenizer": "standard",
"filter": ["lowercase", "substring"]
}
},
"filter": {
"substring": {
"type": "nGram",
"min_gram": 1,
"max_gram": 15
}
}
}
},
"mappings": {
"test": {
"properties": {
"full_name": {
"type": "string",
"analyzer": "substring_analyzer"
},
"address": {
"type": "string",
"analyzer": "substring_analyzer"
},
"description": {
"type": "string",
"analyzer": "substring_analyzer"
}
}
}
}
}'
Then you can index a few docs:
curl -XPUT localhost:9200/tests/test/_bulk -d '
{"index":{"_id": 1}}
{"full_name": "Doe", "address": "1234 Quinn Street", "description": "Lovely guy"}
{"index":{"_id": 2}}
{"full_name": "Brennan", "address": "4567 Main Street", "description": "Not qualified"}
{"index":{"_id": 3}}
{"full_name": "Quantic", "address": "1234 Quinn Street", "description": "New friend"}
'
Finally, you can search with a query equivalent to your SQL query above and all three test documents will match:
curl -XPUT localhost:9200/tests/test/_search -d '{
"query": {
"bool": {
"should": [
{
"match": {
"full_name": "q"
}
},
{
"match": {
"address": "q"
}
},
{
"match": {
"description": "q"
}
}
]
}
}
}'
You can try the following. . .
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html
`
{
"wildcard" : { "user" : "ki*y" }
}
`

Categories