How to store terms to search on those terms in the ElasticSearch? - elasticsearch

I have a requirement where the search should be made on some specific terms. For example,
{
"_index":"idx_name",
"_type":"_doc",
"_id":"82000223323",
"_score":1,
"_source":{
"title":"where is my card?"
}
}
Assuming the above document is in Elasticsearch, I need to fetch this document whenever there is a query on either debit or credit keywords. So, How do I go about solving this in ES? What would be the mapping for that new field and what would be the right query?

You can create a new field called card_type to index types debit and/or credit.
So, you can use Term Query to filter results by each type.
Mapping
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"card_type": {
"type": "keyword"
}
}
}
}
POST my-index-000001/_doc
{
"title": "where is my card?",
"card_type": "debit"
}
OR
POST my-index-000001/_doc
{
"title": "any value here",
"card_type": ["debit", "credit"]
}
The new query filter by type debit.
GET my-index-000001/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"card_type": "debit"
}
}
],
"must": [
{
"match": {
"title": "where is my card?"
}
}
]
}
}
}

Related

Elasticsearch match query on each separate value in a multi value field without nested

For a multi-valued field, like this:
PUT match_test
{
"mappings": {
"properties": {
"companies": {
"type": "text"
}
}
}
}
POST match_test/_doc/1
{
"companies": ["bank of canada", "japan games and movies", "microsoft canada"]
}
This query returns the document we inserted above:
GET match_test/_search
{
"query": {
"match": {
"companies": {
"query": "canada games",
"operator": "and"
}
}
}
}
Is there any way to tell elastic to match to each item in the list separately?
I want the doc to match "bank of", "of America", "bank", "games", "Canada", but not "Microsoft games"
I do not want to use nested documents or scripts
If you want to find words that are far apart from each other but are still on the same array index , then you can use position_increment_gap.
When creating a mapping, set position_increment_gap of the field to 100. Elasticsearch will automatically index array data at each position with +100 in position for the data at the next index.
Then write a match_phrase query with slop 99.
PUT match_test
{
"mappings": {
"properties": {
"companies": {
"type": "text",
"position_increment_gap": 100
}
}
}
}
GET match_test/_search
{
"query": {
"match_phrase": {
"companies": {
"query": "japan movies",
"slop":99
}
}
}
}
Read more about it here https://www.elastic.co/guide/en/elasticsearch/reference/current/position-increment-gap.html

Proximity-Relevance in elasticsearch

I have an json record in the elastic search with fields
"streetName": "5 Street",
"name": ["Shivam Apartments"]
I tried the below query but it does not return anything if I add streetName bool in the query
{
"query": {
"bool": {
"must": [
{
"bool": {
"must": {
"match": {
"name": {
"query": "shivam apartments",
"minimum_should_match": "80%"
}
}
}
}
},
{
"bool": {
"must": {
"match": {
"streetName": {
"query": "5 street",
"minimum_should_match": "80%"
}
}
}
}
}
]
}
}
}
Document Mapping
{
"rabc_documents": {
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "autocomplete_analyzer",
"position_increment_gap": 0
},
"streetName": {
"type": "keyword"
}
}
}
}
}
Based on the E.S Documentation (Keywords in Elastic Search)
"Keyword fields are only searchable by their exact value".
Along with that keywords are case sensitive as well.
Taking aforementioned into account:
Searching for "5 street" will not match "5 Street" ('s' vs 'S') on keyword field
minimum_should_match will not work on a keyword field.
Suggestion: For partial matches use "text" mapping instead of "keyword". Keywords are meant to be used for filtering, aggregation based on term, etc.

Elasticsearch - Mapping fields from other indices

How can I define mapping in Elasticsearch 7 to index a document with a field value from another index? For example, if I have a users index which has a mapping for name, email and account_number but the account_number value is actually in another index called accounts in field number.
I've tried something like this without much success (I only see "name", "email" and "account_id" in the results):
PUT users/_mapping
{
"properties": {
"name": {
"type": "text"
},
"email": {
"type": "text"
},
"account_id": {
"type": "integer"
},
"accounts": {
"properties": {
"number": {
"type": "text"
}
}
}
}
}
The accounts index has the following mapping:
{
"properties": {
"name": {
"type": "text"
},
"number": {
"type": "text"
}
}
}
As I understand it, you want to implement field joining as is usually done in relational databases. In elasticsearch, this is possible only if the documents are in the same index. (Link to doc). But it seems to me that in your case you need to work differently, I think your Account object needs to be nested for User.
PUT /users/_mapping
{
"mappings": {
"properties": {
"account": {
"type": "nested"
}
}
}
}
You can further search as if it were a separate document.
GET /users/_search
{
"query": {
"nested": {
"path": "account",
"query": {
"bool": {
"must": [
{ "match": { "account.number": 1 } }
]
}
}
}
}
}

Is is possible to term query with asciifolding?

I would need to match the whole field but using lowercase and asciifolding token filters. Is this possible in Elasticsearch?
For example, if I have a "Title" field for products and the product title is "Potovalni Kovček". And the user search query is "potovalni kovcek" then I need to return this product as the result. But only if the whole title matches the search query. If the user search query is "potovalni" or "Potovalni" or "kovcek" no results should be returned.
Can I create a term query with lowercase and asciifolding token filters? I couldn't figure out how to do that.
What I would do is to define the title field as a keyword and use a custom normalizer to do the job.
First let's create the index:
PUT test
{
"settings": {
"analysis": {
"normalizer": {
"exact": {
"type": "custom",
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
},
"mappings": {
"doc": {
"properties": {
"title": {
"type": "keyword",
"normalizer": "exact"
}
}
}
}
}
Then, we index a sample document:
PUT test/doc/1
{
"title": "Potovalni Kovček"
}
Finally, we can search:
# Record 1 is returned
POST test/_search
{
"query": {
"term": {
"title": "Potovalni Kovček"
}
}
}
# Record 1 is returned
POST test/_search
{
"query": {
"term": {
"title": "potovalni kovcek"
}
}
}
# No record is returned
POST test/_search
{
"query": {
"term": {
"title": "potovalni"
}
}
}
# No record is returned
POST test/_search
{
"query": {
"term": {
"title": "kovcek"
}
}
}

Elasticsearch Query Filter for Word Count

I am currently looking for a way to return documents with a maximum of n words in a certain field.
The query could look like this for a resultset that contains documents with less than three words in the "name" field but there is nothing like word_count as far as I know.
Does anyone know how to handle this, maybe even in a different way?
GET myindex/myobject/_search
{
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"word_count": {
"name": {
"lte": 3
}
}
}
]
}
},
"query": {
"match_all" : { }
}
}
}
}
You can use the token_count data type in order to index the number of tokens in a given field and then search on that field.
# 1. create the index/mapping with a token_count field
PUT myindex
{
"mappings": {
"myobject": {
"properties": {
"name": {
"type": "string",
"fields": {
"word_count": {
"type": "token_count",
"analyzer": "standard"
}
}
}
}
}
}
}
# 2. index some documents
PUT index/myobject/1
{
"name": "The quick brown fox"
}
PUT index/myobject/2
{
"name": "brown fox"
}
# 3. the following query will only return document 2
POST myindex/_search
{
"query": {
"range": {
"name.word_count": { 
"lt": 3
}
}
}
}

Resources