Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elasticsearch | copy_to with partial searching

I have copy_to working properly for exact matches but I am unable to properly set it up with partial matches. Below is my mappings/settings and query with expected and actual results.

settings:

{
   "test": {
      "settings": {
         "index": {
            "analysis": {
               "filter": {
                  "ngram_filter": {
                     "type": "edge_ngram",
                     "min_gram": "1",
                     "max_gram": "15"
                  }
               },
               "analyzer": {
                  "ngram_analyzer": {
                     "filter": [
                        "lowercase",
                        "ngram_filter"
                     ],
                     "type": "custom",
                     "tokenizer": "standard"
                  }
               }
            },
            "number_of_shards": "1",
            "number_of_replicas": "1",
           }
      }
   }
}

mappings:

POST /test/_mapping/name
{
   "name": {
      "properties": {
         "vital": {
            "properties": {
               "first": {
                  "type": "string",
                  "copy_to": "full_name",
                   "term_vector": "yes",
                    "analyzer": "ngram_analyzer",
                    "search_analyzer": "standard"
               },
               "last": {
                  "type": "string",
                  "copy_to": "full_name",
                   "term_vector": "yes",
                    "analyzer": "ngram_analyzer",
                    "search_analyzer": "standard"
               },
               "full_name": {
                  "type": "string",
                   "term_vector": "yes",
                    "analyzer": "ngram_analyzer",
                    "search_analyzer": "standard"
               }
            }
         }
      }
   }
}

POST:

POST /test/name 
{
   "vital": {
      "first": "Tom",
      "last": "Doe"
   }
}

Now when I do the search ...

GET /test/name/_search
{
  "query": {
    "match": {
      "full_name": { 
        "query": "Tom Doe",
        "operator": "and"
      }
    }
  }
}

... I get back the result!! Hurrraaaay, but if I do the search ....

GET /test/name/_search
{
  "query": {
    "match": {
      "full_name": { 
        "query": "Tom Do",
        "operator": "and"
      }
    }
  }
}

... I get back no result :( I would like partial matching to work for full_name as well. As another not I am successfully able to due partial matching on first and last name. It is just full_name that is not working. How would I go about this?

like image 479
emarel Avatar asked Jan 23 '17 23:01

emarel


2 Answers

You have one little mistake in your mapping, you need to copy the first and last names into the vital.full_name field, not just full_name, otherwise that will create a new string field named full_name with a standard analyzer at the top-level of your mapping (if you run GET test you'll see that new field in your mapping):

POST /test/_mapping/name
{
   "name": {
      "properties": {
         "vital": {
            "properties": {
               "first": {
                  "type": "string",
                  "copy_to": "vital.full_name",      <--- fix this
                   "term_vector": "yes",
                    "analyzer": "ngram_analyzer",
                    "search_analyzer": "standard"
               },
               "last": {
                  "type": "string",
                  "copy_to": "vital.full_name",      <--- fix this
                   "term_vector": "yes",
                    "analyzer": "ngram_analyzer",
                    "search_analyzer": "standard"
               },
               "full_name": {
                  "type": "string",
                   "term_vector": "yes",
                    "analyzer": "ngram_analyzer",
                    "search_analyzer": "standard"
               }
            }
         }
      }
   }
}

And then fix your queries like this:

POST /test/name/_search
{
  "query": {
    "match": {
      "vital.full_name": {          <-- fix this
        "query": "Tom Doe",
        "operator": "and"
      }
    }
  }
}

POST /test/name/_search
{
  "query": {
    "match": {
      "vital.full_name": {          <-- fix this
        "query": "Tom Do",
        "operator": "and"
      }
    }
  }
}

Both will work as you expect.

like image 96
Val Avatar answered Nov 07 '22 13:11

Val


Just drop "search_analyzer": "standard" from you mappings, it's something required only in certain use cases, like autocomplete searches. See explanation here https://www.elastic.co/guide/en/elasticsearch/guide/master/_index_time_search_as_you_type.html

like image 21
xeye Avatar answered Nov 07 '22 13:11

xeye