Search code examples
nestelasticsearch-6

MostFields multi_match fuzziness on all but one field


I have several different mappings for a field. I have one field that is phonetic. I would like to do a query with fuzziness, but not use fuzziness on the phonetic field.

...
_client.Search<JobModelSummary>(s => s
  .Index(indexName)
  .Query(q => q
    .MultiMatch(m => m
      .Query(paginationQuery.Search)
      .Type(TextQueryType.MostFields)
      .Fuzziness(Fuzziness.EditDistance(1))
      .Fields(f => f
        .Field(ff => ff.Name.Suffix("standard"), 3)
        .Field(ff => ff.Name.Suffix("edge-ngram"), 2)
        .Field(ff => ff.Name.Suffix("phonetic"))  // <--- Don't want this fuzzy
))));

The documentation is sparse and I am finding it difficult to peace together how this would be done.


Solution

  • If you're performing a most fields multi_match query as above, you can achieve what you'd like by combining several match queries together

    var indexName = "foo";
    var search = "search";
    
    var searchResponse client.Search<JobModelSummary>(s => s
        .Index(indexName)
        .Query(q => q
            .Bool(b => b
                .Should(sh => sh
                    .Match(m => m
                        .Query(search)
                        .Fuzziness(Fuzziness.EditDistance(1))
                        .Field(ff => ff.Name.Suffix("standard"))
                        .Boost(3)
                    ), sh => sh
                    .Match(m => m
                        .Query(search)
                        .Fuzziness(Fuzziness.EditDistance(1))
                        .Field(ff => ff.Name.Suffix("edge-ngram"))
                        .Boost(2)
                    ), sh => sh
                    .Match(m => m
                        .Query(search)
                        .Field(ff => ff.Name.Suffix("phonetic"))
                    )
                )
            )   
        )
    );
    

    which can be made slightly more succinct with using the overload operators for queries

    client.Search<JobModelSummary>(s => s
        .Index(indexName)
        .Query(q => q
            .Match(m => m
                .Query(search)
                .Fuzziness(Fuzziness.EditDistance(1))
                .Field(ff => ff.Name.Suffix("standard"))
                .Boost(3)
            ) || q
            .Match(m => m
                 .Query(search)
                 .Fuzziness(Fuzziness.EditDistance(1))
                 .Field(ff => ff.Name.Suffix("edge-ngram"))
                 .Boost(2)
            ) || q
            .Match(m => m
                 .Query(search)
                 .Field(ff => ff.Name.Suffix("phonetic"))
            )
        )
    );
    

    Both produce

    POST http://localhost:9200/foo/jobmodelsummary/_search 
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
                "name.standard": {
                  "boost": 3.0,
                  "query": "search",
                  "fuzziness": 1
                }
              }
            },
            {
              "match": {
                "name.edge-ngram": {
                  "boost": 2.0,
                  "query": "search",
                  "fuzziness": 1
                }
              }
            },
            {
              "match": {
                "name.phonetic": {
                  "query": "search"
                }
              }
            }
          ]
        }
      }
    }
    

    The scores for each query in the should clause will be added together to provide the final _score for each document. With only should clauses specified, at least one has to match for a document to be considered a match.