If you're using PlainElastic.Net, I would recommend asking the authors of that library about how to change the analyzer on a field mapping. It is not a library that Elastic maintains.
With NEST, the official high level .NET client for Elasticsearch, the following would create an index with the desired mappings (using NEST 2.3.2 targeting Elasticsearch 2.x)
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
// map Tweet type to index "twitter". This will be the default index used
// when the type in the search is Tweet and no index is specified on the request
var connectionSettings = new ConnectionSettings(pool)
.MapDefaultTypeIndices(d => d.Add(typeof(Tweet), "twitter"));
var client = new ElasticClient(connectionSettings);
var createIndexResponse = client.CreateIndex("twitter", c => c
.Settings(s => s
.NumberOfShards(8)
.NumberOfReplicas(1)
)
.Mappings(m => m
.Map<Tweet>(tm => tm
// infer mapping for all properties
.AutoMap()
// now override any inferred mappings that we want to change
.Properties(p => p
// set "user" field as a multi_field:
// - "user" will be indexed using the standard analyzer
// - "user.keyword" will be indexed using the keyword analyzer
// - "user.raw" will be indexed with analysis
.String(s => s
.Name(n => n.User)
.Fields(f => f
.String(sf => sf
.Name("keyword")
.Analyzer("keyword")
)
.String(sf => sf
.Name("raw")
.NotAnalyzed()
)
)
)
// similarly, set "message" field as a multi_field:
.String(s => s
.Name(n => n.Message)
.Fields(f => f
.String(sf => sf
.Name("keyword")
.Analyzer("keyword")
)
.String(sf => sf
.Name("raw")
.NotAnalyzed()
)
)
)
)
)
)
);
// index these three documents
var tweets = new[] {
new Tweet
{
User = "forloop",
Message = "This is an apple",
Date = new DateTime(2016, 6, 8, 13, 52, 0)
},
new Tweet
{
User = "mpdreamz",
Message = "This is an apple in my hand",
Date = new DateTime(2016, 6, 8, 13, 50, 0)
},
new Tweet
{
User = "gregmarzouka",
Message = "This is not an apple",
Date = new DateTime(2016, 6, 8, 13, 54, 0)
},
};
var bulkResponse = client.Bulk(b => b
.IndexMany(tweets, (i, d) => i.Document(d))
.Refresh()
);
// match query on "message.keyword" field
var searchResonse = client.Search<Tweet>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.Message.Suffix("keyword"))
.Query("This is an apple")
)
)
);
Console.WriteLine("Found {0} matching document(s)", searchResonse.Total);
Console.WriteLine("Matching document users: {0}", string.Join(",", searchResonse.Documents.Select(d => d.User)));
}
public class Tweet
{
public string User { get; set; }
public string Message { get; set; }
public DateTime Date { get; set; }
}
The result of running the match query is
Found 1 matching document(s)
Matching document users: forloop
as expected.