Search code examples
elasticsearchelasticsearch-6elasticsearch-mapping

Is there any way to add the field in document but hide it from _source, also document should be analysed and searchable


I want to add one field to the document which should be searchable but when we do get/search it should not appear under _source.

I have tried index and store options but its not achievable through it. Its more like _all or copy_to, but in my case value is provided by me (not collecting from other fields of the document.)

I am looking for mapping through which I can achieve below cases.

When I put document :

PUT my_index/_doc/1
{
  "title":   "Some short title",
  "date":    "2015-01-01",
  "content": "A very long content field..."
}

and do search

GET my_index/_search

output should be

{
    "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "title" : "Some short title",
          "date" : "2015-01-01"
        }
      }
    ]
  }
}

also when I do the below search

GET my_index/_search
{
  "query": {
    "query_string": {
      "default_field": "content",
      "query": "long content"
    }
  }
}

it should result me

"hits" : {
    "total" : 1,
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.5753642,
        "_source" : {
          "title" : "Some short title",
          "date" : "2015-01-01"
        }
      }
    ]
  }

Solution

  • We can achieve this using below mapping :

    PUT my_index
    {
      "mappings": {
    
        "_doc": {
          "_source": {
            "excludes": [
              "content"
            ]
          },
          "properties": {
            "title": {
              "type": "text",
              "store": true 
            },
            "date": {
              "type": "date",
              "store": true 
            },
            "content": {
              "type": "text"
            }
          }
        }
      }
    }
    

    Add document :

    PUT my_index/_doc/1
    {
      "title":   "Some short title",
      "date":    "2015-01-01",
      "content": "A very long content field..."
    }
    

    When you run the query to search content on the field 'content' :

    GET my_index/_search
    {
      "query": {
        "query_string": {
          "default_field": "content",
          "query": "long content"
        }
      }
    }
    

    You will get the result with hits as below:

    "hits" : {
        "total" : 1,
        "max_score" : 0.5753642,
        "hits" : [
          {
            "_index" : "my_index",
            "_type" : "_doc",
            "_id" : "1",
            "_score" : 0.5753642,
            "_source" : {
              "date" : "2015-01-01",
              "title" : "Some short title"
            }
          }
        ]
      }
    

    It hides the field 'content'. :)

    Hence achieved it with the help of mapping. You don't need to exclude it from query each time you make get/search call.

    More read on source : https://www.elastic.co/guide/en/elasticsearch/reference/6.6/mapping-source-field.html