You need a multifield and multimatch request.
I have the same problem. I had to search by name, so if I put the search term βANDβ, I get the first βAndy,β not βMandy.β With just nGram, I couldn't achieve this.
I added another analyzer that uses the cutting edge of NGram (the code below is for Spring Data Elasticsearch, but you can get this idea).
setting.put("analysis.analyzer.word_parts.type", "custom"); setting.put("analysis.analyzer.word_parts.tokenizer", "ngram_tokenizer"); setting.put("analysis.analyzer.word_parts.filter", "lowercase"); setting.put("analysis.analyzer.type_ahead.type", "custom"); setting.put("analysis.analyzer.type_ahead.tokenizer", "edge_ngram_tokenizer"); setting.put("analysis.analyzer.type_ahead.filter", "lowercase"); setting.put("analysis.tokenizer.ngram_tokenizer.type", "nGram"); setting.put("analysis.tokenizer.ngram_tokenizer.min_gram", "3"); setting.put("analysis.tokenizer.ngram_tokenizer.max_gram", "50"); setting.put("analysis.tokenizer.ngram_tokenizer.token_chars", new String[] { "letter", "digit" }); setting.put("analysis.tokenizer.edge_ngram_tokenizer.type", "edgeNGram"); setting.put("analysis.tokenizer.edge_ngram_tokenizer.min_gram", "2"); setting.put("analysis.tokenizer.edge_ngram_tokenizer.max_gram", "20");
I displayed the required fields as multiple fields:
@MultiField(mainField = @Field(type = FieldType.String, indexAnalyzer = "word_parts", searchAnalyzer = "standard"), otherFields = @NestedField(dotSuffix = "autoComplete", type = FieldType.String, searchAnalyzer = "standard", indexAnalyzer = "type_ahead")) private String firstName;
For the request, I use multimatch, I first specify 'firstName.autoComplete', and not just 'firstName'
QueryBuilders.multiMatchQuery(searchTerm, new String[]{"firstName.autoComplete", "firstName"})
It seems to work correctly.
In your case, if you need an exact match, perhaps instead of "edgeNGram" you can use only "standard".