NEST的Elasticsearch查询无法正常工作

时间:2017-03-02 09:36:43

标签: c# sql-server asp.net-mvc elasticsearch nest

我使用Microsoft SQL Server Management Studio和ElasticSearch 2.3.4与ElasticSearch-jdbc-2.3.4.1,我将ES与我的mssql服务器相关联。一切正常,但当我在我的MVC程序上使用NEST进行查询时,结果为空。当我在我的search属性中放入一个空字符串时,我得到了元素,但是当我尝试用一​​些过滤器填充它时,我得到一个空的结果。有人可以帮帮我吗?提前谢谢。

C#:

const string ESServer = "http://localhost:9200";
ConnectionSettings settings = new ConnectionSettings(new Uri(ESServer));
settings.DefaultIndex("tiky");
settings.MapDefaultTypeNames(map => map.Add(typeof(DAL.Faq), "faq"));
ElasticClient client = new ElasticClient(settings);

var response = client.Search<DAL.Faq>(s => s.Query(q => q.Term(x => x.Question, search)));

var result = response.Documents.ToList();

DAL: DAL

邮差: PostMan

PS:我跟着this guide创建了

修改

索引映射:Index Mapping

1 个答案:

答案 0 :(得分:2)

There's a couple of things that I can see that may help here:

  1. By default, NEST camel cases POCO property names when serializing them as part of the query JSON in the request, so x => x.Question will serialize to "question". Looking at your mapping however, field names in Elasticsearch are Pascal cased, so what the client is doing will not match what's in Elasticsearch.

You can change how NEST serializes POCO property names by using .DefaultFieldNameInferrer(Func<string, string>) on ConnectionSettings

const string ESServer = "http://localhost:9200";
ConnectionSettings settings = new ConnectionSettings(new Uri(ESServer))
    .DefaultIndex("tiky");
    .MapDefaultTypeNames(map => map.Add(typeof(DAL.Faq), "faq"))
    // pass POCO property names through verbatim
    .DefaultFieldNameInferrer(s => s);

ElasticClient client = new ElasticClient(settings);
  1. As Rob mentioned in the comments, a term query does not analyze the query input. When executing a term query against a field that is analyzed at index time then, in order to get matches, the query text that you pass to the term query would need to take the analysis that is applied at index time into account. For example,

    • Question is analyzed with the Standard Analyzer
    • A Question value of "What's the Question?" will be analyzed and indexed as tokens "what's", "the" and "question"
    • A term query would need to have a query input of "what's", "the" or "question" to be a match

A match query, unlike a term query, does analyze the query input, so the output of the search analysis will be used to find matches. In conjunction with Pascal casing highlighted in 1., you should now get documents returned.

You can also have the best of both worlds in Elasticsearch i.e. analyze input at index time for full-text search functionality as well as index input without analysis to get exact matches. This is done with multi-fields and here is an example of creating a mapping that indexes Question properties as both analyzed and not analyzed

public class Faq
{
    public string Question { get; set; }
}

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "default-index";
var connectionSettings = new ConnectionSettings(pool)
        .DefaultIndex(defaultIndex)
        .DefaultFieldNameInferrer(s => s);

var client = new ElasticClient(connectionSettings);

if (client.IndexExists(defaultIndex).Exists)
    client.DeleteIndex(defaultIndex);

client.CreateIndex(defaultIndex, c => c
    .Mappings(m => m
        .Map<Faq>(mm => mm
            // let NEST infer mapping from the POCO
            .AutoMap()
            // override any inferred mappings explicitly
            .Properties(p => p
                .String(s => s
                    .Name(n => n.Question)
                    .Fields(f => f
                        .String(ss => ss
                            .Name("raw")
                            .NotAnalyzed()
                        )
                    )
                )
            )
        )
    )
);   

The mapping for this looks like

{
  "mappings": {
    "faq": {
      "properties": {
        "Question": {
          "type": "string",
          "fields": {
            "raw": {
              "type": "string",
              "index": "not_analyzed"
            }
          }
        }
      }
    }
  }
}

The "raw" sub field under the "Question" field will index the value of the Question property without any analysis i.e. verbatim. This sub field can now be used in a term query to find exact matches

client.Search<Faq>(s => s
    .Query(q => q
        .Term(f => f.Question.Suffix("raw"), "What's the Question?")
    )
);

which find matches for the previous example.