c# - ElasticSearch match list and Fuzziness - Stack Overflow

admin2025-04-22  5

I have items in my ElasticSearch as follows:

{
"superItems_1": {
    "mappings": {
        "properties": {
            "aliasNames": {
                "type": "keyword",
                "normalizer": "lowercase_normalizer"
            },
            "typeCode": {
                "type": "text"
            },
            "mainName": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            }
        }
    }
}}

What I want is to do searches to this ElasticSearch in two ways.

First, just do fuzzysearch against aliasNames and mainNames and ignore the typeCode. Here's my current implementation in C#:

    var withoutTypeIdentifier = await ESClient.SearchAsync<ElasticSearchEntity>(s => s
    .Index(indexName)
    .Query(q => q.Bool(b => b
        .Should(
            should => should.Match(m => m
                .Field(f => f.MainName)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("Auto"))
                .PrefixLength(0)
                .MaxExpansions(50)
            ),
            should => should.Match(m => m
                .Field(f => f.AliasNames)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("Auto"))
                .PrefixLength(0)
                .MaxExpansions(50)
            )
        )
    )));

This works nicely, but here's the issue:

THEN, I want to add the typeCodes, which I have as a List<string> typeCodes, So if the SuperItems has an item with TypeCode: "OUTDATED", and user searches for {"OUTDATED","DELETED"} it will match with the "OUTDATED". Every item has this TypeCode. Here's my attempt, but I can not figure out how to give the entire list:

var searchResponse = await ESClient.SearchAsync<ElasticSearchEntity>(s => s
.Index(indexName)
.Query(q => q.Bool(b => b
        .Must(m => m
            .Term(t => t
                .Field(f => f.TypeCodes.Suffix("keyword")) 
                .Value(typeCodes) <--- How ???
            )
        )
        .Should(
            should => should.Match(m => m
                .Field(f => f.FullName)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("AUTO"))
                .PrefixLength(0)
                .MaxExpansions(50)
            ),
            should => should.Match(m => m
                .Field(f => f.AliasNames)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("AUTO"))
                .PrefixLength(0)
                .MaxExpansions(50)
            )
        )
        
)));

Of course I asked from the AI, but that thing just keeps telling me to use this implementation, which does not work, and has ambiguous invocations, and it just can't fix it no matter what I ask.

var searchResponse = await ESClient.SearchAsync<ElasticSearchEntity>(s => s
    .Index(indexName)
    .Query(q => 
      q.Bool(b => b
        .Must(m => m.Terms(c => c       <-- This gives an error: Ambiquous invocation
            .Field("typeCodes.keyword")
            .Terms(typeCodes)
        ))
        .Should(
            sh => sh.Match(d => d
                .Field("fullName")
                .Query(searchValue)
                .Fuzziness("AUTO")
              ETC...

I'm using the latest Elastic.Clients.Elasticsearch;

Any thoughts on how to implement this?

I have items in my ElasticSearch as follows:

{
"superItems_1": {
    "mappings": {
        "properties": {
            "aliasNames": {
                "type": "keyword",
                "normalizer": "lowercase_normalizer"
            },
            "typeCode": {
                "type": "text"
            },
            "mainName": {
                "type": "text",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            }
        }
    }
}}

What I want is to do searches to this ElasticSearch in two ways.

First, just do fuzzysearch against aliasNames and mainNames and ignore the typeCode. Here's my current implementation in C#:

    var withoutTypeIdentifier = await ESClient.SearchAsync<ElasticSearchEntity>(s => s
    .Index(indexName)
    .Query(q => q.Bool(b => b
        .Should(
            should => should.Match(m => m
                .Field(f => f.MainName)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("Auto"))
                .PrefixLength(0)
                .MaxExpansions(50)
            ),
            should => should.Match(m => m
                .Field(f => f.AliasNames)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("Auto"))
                .PrefixLength(0)
                .MaxExpansions(50)
            )
        )
    )));

This works nicely, but here's the issue:

THEN, I want to add the typeCodes, which I have as a List<string> typeCodes, So if the SuperItems has an item with TypeCode: "OUTDATED", and user searches for {"OUTDATED","DELETED"} it will match with the "OUTDATED". Every item has this TypeCode. Here's my attempt, but I can not figure out how to give the entire list:

var searchResponse = await ESClient.SearchAsync<ElasticSearchEntity>(s => s
.Index(indexName)
.Query(q => q.Bool(b => b
        .Must(m => m
            .Term(t => t
                .Field(f => f.TypeCodes.Suffix("keyword")) 
                .Value(typeCodes) <--- How ???
            )
        )
        .Should(
            should => should.Match(m => m
                .Field(f => f.FullName)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("AUTO"))
                .PrefixLength(0)
                .MaxExpansions(50)
            ),
            should => should.Match(m => m
                .Field(f => f.AliasNames)
                .Query(searchValue)
                .Fuzziness(new Fuzziness("AUTO"))
                .PrefixLength(0)
                .MaxExpansions(50)
            )
        )
        
)));

Of course I asked from the AI, but that thing just keeps telling me to use this implementation, which does not work, and has ambiguous invocations, and it just can't fix it no matter what I ask.

var searchResponse = await ESClient.SearchAsync<ElasticSearchEntity>(s => s
    .Index(indexName)
    .Query(q => 
      q.Bool(b => b
        .Must(m => m.Terms(c => c       <-- This gives an error: Ambiquous invocation
            .Field("typeCodes.keyword")
            .Terms(typeCodes)
        ))
        .Should(
            sh => sh.Match(d => d
                .Field("fullName")
                .Query(searchValue)
                .Fuzziness("AUTO")
              ETC...

I'm using the latest Elastic.Clients.Elasticsearch;

Any thoughts on how to implement this?

Share Improve this question asked Jan 21 at 14:38 DeadlyHighDeadlyHigh 1189 bronze badges 1
  • "This works nicely, but here's the issue:" - what issue? :) seems like you missed the part – Kiryl Commented Jan 23 at 9:56
Add a comment  | 

1 Answer 1

Reset to default 0

The type of typeCode is text. Therefore your first way is to use the match query. I demonstrate it in the terms of Elasticsearch queries, not c#.

Sample documents

POST /only_text_field/_bulk
{"create":{}}
{"typeCode":"OUTDATED"}
{"create":{}}
{"typeCode":"DELETED"}
{"create":{}}
{"typeCode":"ANOTHER"}

match query with a list of values converted into a string

GET /only_text_field/_search?filter_path=hits.hits._source
{
    "query": {
        "match": {
            "typeCode": "OUTDATED DELETED"
        }
    }
}

Response

{
    "hits" : {
        "hits" : [
            {
                "_source" : {
                    "typeCode" : "OUTDATED"
                }
            },
            {
                "_source" : {
                    "typeCode" : "DELETED"
                }
            }
        ]
    }
}

Your second way is to update mapping with converting typeCode into a multi-field with the keyword representation. Then you should use the terms query

GET /only_text_field/_search?filter_path=hits.hits._source
{
    "query": {
        "terms": {
            "typeCode.keyword": ["OUTDATED", "DELETED"]
        }
    }
}

Response

{
    "hits" : {
        "hits" : [
            {
                "_source" : {
                    "typeCode" : "OUTDATED"
                }
            },
            {
                "_source" : {
                    "typeCode" : "DELETED"
                }
            }
        ]
    }
}
转载请注明原文地址:http://anycun.com/QandA/1745303911a90618.html