2

I'm a newb to ES... found a tutorial online:

PUT /company
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    },
    "analysis": {
      "analyzer": {
        "analyzer-name": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": "lowercase"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "experienceInYears": {
        "type": "integer"
      },
      "name": {
        "type": "keyword",
        "analyzer": "analyzer-name"
      }
    }
  }
}

What is wrong with this? I get the following errors:

{
  "error": {
    "root_cause": [
      {
        "type": "mapper_parsing_exception",
        "reason": "Mapping definition for [name] has unsupported parameters:  [analyzer : analyzer-name]"
      }
    ],
    "type": "mapper_parsing_exception",
    "reason": "Failed to parse mapping [_doc]: Mapping definition for [name] has unsupported parameters:  [analyzer : analyzer-name]",
    "caused_by": {
      "type": "mapper_parsing_exception",
      "reason": "Mapping definition for [name] has unsupported parameters:  [analyzer : analyzer-name]"
    }
  },
  "status": 400
}

I get that the field analyzer is causing the issue :), but isn't that correct?

SledgeHammer
  • 7,338
  • 6
  • 41
  • 86

4 Answers4

1

The keyword datatype doesn't have an analyzer parameter, the text datatype has.

Checkout the allowed parameters in the docs for both datatypes:

So your name property mapping should change to this.

  ...
  "name": {
    "type": "text",
    "analyzer": "analyzer-name"
  }
  ...
Rodrigo García
  • 1,357
  • 15
  • 26
1

Although the cause of the error is already pointed and one way to avoid solution is also mentioned, I just want to make sure that you understand the other way to solve the issue and understand the pros and cons of it, As you are new to ES.

Indexing part

Keyword fields are stored as it is, it means it wouldn't go through the analysis process, Hence text present in your field would be stored as it is in the inverted index of ES, which is used for searching and ES searching is based on token matches. But if you define a field as text, and don't specify an analyzer ES default analyzer which is standard analyzer would be used, In either case, your text would go through the analysis phase which I mentioned and resultant tokens would be stored in Inverted index.

Searching part

Now field types play an important role, how your search will be executed. refer This SO answer for more info. In short, search query also go through the analysis phase which again depends on various factor and generated search tokens which would be matched against indexed tokens. Hence it's important to understand the entire use case before deciding what type of field and what analyzer to used.

Btw another solution for you to just define your name field as a keyword field which you can do by changing the structure to below:

"name": {
    "type": "keyword" // notice I removed analyzer section.
  }
Amit
  • 30,756
  • 6
  • 57
  • 88
1

As other members said : The keyword datatype doesn't have an analyzer parameter.

It seems to me you wanted to create a lowercase analyzer for your keyword field type.

In order to do so you should create a normalizer (for keyword types).

Normalizer

A working example:

Create mappings with normalizer:

PUT /company
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    },
    "analysis": {
      "normalizer": {
        "my_normalizer": {
          "filter": [
            "lowercase"
          ],
          "type": "custom"
        }
      },
      "analyzer": {
        "analyzer-name": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": "lowercase"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "experienceInYears": {
        "type": "integer"
      },
      "name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "normalizer": "my_normalizer"
          }
        }
      }
    }
  }
}

Let's post a document:

POST company/_doc/1
{
  "name":"WwW.CoM"
}

As you can see name value is combined with lowercase and uppercase letters.

Without the normalizer you could not be able to look for www.com, cause keyword type looks for exact match.

Let's execute our search query:

GET company/_search
{
  "query": {
    "term": {
      "name.keyword": {
        "value": "www.com"
      }
    }
  }
}

Results:

{
 "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "company",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "name" : "WwW.CoM"
        }
      }
    ]
  }
}

I hope this is what you've wanted to achieve.

Assael Azran
  • 2,863
  • 1
  • 9
  • 13
1

keyword datatype does not support analyser parameter.

PUT /company
{
  "settings": {
    "index": {
      "number_of_shards": 1,
      "number_of_replicas": 1
    },
    "analysis": {
      "analyzer": {
        "analyzer-name": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": "lowercase"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "age": {
        "type": "integer"
      },
      "experienceInYears": {
        "type": "integer"
      },
      "name": {
        "type": "text",
        "analyzer": "analyzer-name"
      }
    }
  }
}
dhamo
  • 545
  • 2
  • 7