Search code examples
c#elasticsearchwildcardnest

Query with multimatch and wildcard


I'm trying to execute a query on multi fields but also using a wildcard in the MobileNumber, basically, if a mobile number is for example 3530831112233 if I search by 831122 I want to return this record. This is what I have done so far.

var response = await this.client.SearchAsync<ElasticCustomer>(searchDescriptor => searchDescriptor
          .AllTypes()
            .Query(q => q
                     .MultiMatch(m => m
                            .Fields(f => f
                                .Field(u => u.CustomerName)
                                .Field(u => u.MobileNumber))
                          .Query(query)))
          .Size(pageSize)
          .Sort(q => q.Descending(u => u.CustomerLastUpdated)));

Solution

  • If you want to perform wildcard query, you will need to use something like wildcard query and combine it with match query on CustomerName field in a bool query.

    Here is the simple app showing usage:

    class Program
    {
        public class Document  
        {
            public int Id { get; set; }
            public DateTime Timestamp { get; set; }
            public string CustomerName { get; set; }
            public string MobileNumber { get; set; }
        } 
    
        static async Task Main(string[] args)
        {
            var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
            var connectionSettings = new ConnectionSettings(pool);
            connectionSettings.DefaultIndex("documents");
    
            var client = new ElasticClient(connectionSettings);
    
            await client.Indices.DeleteAsync("documents");
            await client.Indices.CreateAsync("documents");
    
            var response = await client.IndexAsync(
                new Document
                {
                    Id = 1, 
                    Timestamp = new DateTime(2010, 01, 01, 10, 0, 0),
                    MobileNumber = "3530831112233",
                    CustomerName = "Robert"
                }, descriptor => descriptor);
    
            await client.Indices.RefreshAsync();
    
            string query = "8311122";
            var result = await client.SearchAsync<Document>(s => s
                .Query(q => q.Bool(b => b
                    .Should(
                        sh => sh.Match(m => m.Field(f => f.CustomerName).Query(query)),
                        sh => sh.Wildcard(w => w.Field(f => f.MobileNumber.Suffix("keyword")).Value($"*{query}*"))))));
    
            foreach (var document in result.Documents)
            {
                Console.WriteLine(document.Id);
            }
        }
    }
    

    Output:

    1
    

    However, I would suggest avoiding the wildcard query whenever you can at it maybe result in query performance degradation.

    As a wildcard substitution, you can have a look at ngram tokenizer or phone number analyzer plugin.

    Hope that helps.