使用 NEST C# 在弹性搜索中使用多个索引进行全文搜索 [英] Full text Search with Multiple index in Elastic Search using NEST C#
问题描述
我正在尝试使用 NEST 客户端搜索多个索引 Elasticsearch,我只需点击以下链接
[stackover post ]如何使用 Nest ElasticSearch 在多个索引中进行搜索?唯一的区别是我的索引已经存在但没有返回
I'm trying to search Multiple indexes Elasticsearch with NEST Client, I just follow the below link
[stackover post ]How to search inside multiple indices using Nest ElasticSearch?
the only difference was my indexes are already existed but nothing returns
示例代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Elasticsearch.Net;
using Nest;
namespace ElasticSearchDemo
{
public class ExceptionData
{
public bool HasException { get; set; }
public string ExceptionMessage { get; set; }
}
public class ElasticSearchResponse : ExceptionData
{
public ISearchResponse<dynamic> elasticSearchResponse { get; set; }
}
public class ComponentTypES
{
public string ComponentID { get; set; }
public string Componentname { get; set; }
public string Summary { get; set; }
}
public class ProjectTypES
{
public string ProjectID { get; set; }
public string Projectname { get; set; }
public string Summary { get; set; }
public string Description { get; set; }
}
class Program
{
static void Main(string[] args)
{
// calling the function
var response = GetAllSearchResults("test", 0, 10);
}
public static ElasticClient GetElasticSearchCommonSearch()
{
ElasticClient elasticClient = null;
try
{
const string strElasticSearchURL = "http://localhost:9200/";
const string componentIndex = "componenttypeindex";
const string projectIndex = "projecttypeindex";
if (!string.IsNullOrEmpty(strElasticSearchURL))
{
ConnectionSettings connectionSettings = new ConnectionSettings(new Uri(strElasticSearchURL))
.DefaultIndex(componentIndex)
.DefaultMappingFor<ComponentTypES>(i => i.IndexName(componentIndex).TypeName("Componenttype"))
.DefaultMappingFor<ProjectTypES>(j => j.IndexName(projectIndex).TypeName("Projecttype"))
.DisableDirectStreaming()
.PrettyJson()
.OnRequestCompleted(callDetails =>
{
if (callDetails.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{callDetails.HttpMethod} {callDetails.Uri} \n" +
$"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
}
Console.WriteLine();
if (callDetails.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
}
);
elasticClient = new ElasticClient(connectionSettings);
}
}
catch (Exception ex)
{
throw new Exception(ex.Message + " ConnectionObject for : Common Search");
}
return elasticClient;
}
public static ElasticSearchResponse GetAllSearchResults(string query = "test", int
page = 1, int pagesize = 10)
{
ElasticSearchResponse combinedResponse = new ElasticSearchResponse();
try
{
ElasticClient elasticClient = GetElasticSearchCommonSearch();
var clusterHealth = elasticClient.ClusterHealth();
if (clusterHealth.IsValid && string.Compare(clusterHealth.Status.ToString(), "red", true) != 0 && clusterHealth.ServerError == null)
{
string Componentindex = "componenttypeindex";
string Projectindex = "projecttypeindex";
var indices = Indices.Index(typeof(ComponentTypES)).And(typeof(ProjectTypES));
//elasticClient.Refresh(indices);
//TODO : Development time coding
if (null != (indices))
{
var indexExists = elasticClient.IndexExists(Indices.Index(Componentindex));
var projectExists = elasticClient.IndexExists(Indices.Index(Projectindex));
if (indexExists.Exists && indexExists.IsValid && projectExists.Exists && projectExists.IsValid)
{
//full text example 1
combinedResponse.elasticSearchResponse = elasticClient.Search<object>(s => s
.Index(indices)
.Type(Types.Type(typeof(ComponentTypES), typeof(ProjectTypES)))
.Query(q => (q
.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<ComponentTypES>(ff => ff.Componentname))
.Field(Infer.Field<ComponentTypES>(ff => ff.Summary, 1.1))
)
.Operator(Operator.Or)
.Query(query)
) && +q
.Term("_index", Componentindex)) || (q
.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<ProjectTypES>(ff => ff.Projectname))
.Field(Infer.Field<ProjectTypES>(ff => ff.Summary, 0.3))
)
.Operator(Operator.Or)
.Query(query)
) && +q
.Term("_index", Projectindex))
).From(page - 1)
.Size(pagesize)
);
//free text example 2
combinedResponse.elasticSearchResponse = elasticClient.Search<object>(s => s
.Index(indices)
.Type(Types.Type(typeof(ComponentTypES), typeof(ProjectTypES)))
.Query(q => (q
.MatchPhrase(m => m
.Field(Infer.Field<ComponentTypES>(ff => ff.Componentname))
.Query(query)
) && +q
.Term("_index", Componentindex)) || (q
.MatchPhrase(m => m
.Field(Infer.Field<ProjectTypES>(ff => ff.Projectname))
.Query(query)
)
) && +q
.Term("_index", Projectindex)
).From(page - 1)
.Size(pagesize)
);
}
else
{
combinedResponse.HasException = true;
combinedResponse.ExceptionMessage = "Index Not Found";
}
}
else
{
combinedResponse.HasException = true;
combinedResponse.ExceptionMessage = "Index Not Found In Config File";
}
}
else
{
combinedResponse.HasException = true;
combinedResponse.ExceptionMessage = "Error on connecting with ElasticSearch";
}
}
catch (Exception ex)
{
combinedResponse.HasException = true;
combinedResponse.ExceptionMessage = ex.Message;
return combinedResponse;
}
return combinedResponse;
}
}
}
弹性表架构:
PUT componenttypeindex
{
"mappings": {
"Componenttype":{
"properties":{
"ComponentID":{"type":"text"},
"Componentname":{"type":"text"},
"Summary":{"type":"text"}
}
}
}
}
PUT projecttypeindex
{
"mappings": {
"Projecttype":{
"properties":{
"ProjectID":{"type":"text"},
"Projectname":{"type":"text"},
"Summary":{"type":"text"},
"Description":{"type":"text"}
}
}
}
}
它应该返回查询匹配的项目,但没有返回抱歉,我尝试了丑陋的代码格式,但新编辑器不会改变任何内容
it should return query matched items, but nothing returns sorry for my ugly code formatting I tried but the new editor won't change anything
更新:我已经按照@RussCam 的建议更新了查询中的索引值,但仍然没有预期的结果,而且当扩展响应对象并直接在浏览器中运行 URI 参数时,它的所有结果都很奇怪,不知道为什么没有显示在响应计数
UPDATE : i've updated the Index values in the query as suggested by @RussCam but still no expected results , and also when expands the response objects and ran the URI parameter in directly in Browser it has all the results something weird not sure why this not shown in response count
从 POST 上成功的低级别调用构建的有效 NEST 响应:/componenttypeindex%2Cprojecttypeindex/Componenttype%2CProjecttype/_search?typed_keys=true
Valid NEST response built from a successful low level call on POST: /componenttypeindex%2Cprojecttypeindex/Componenttype%2CProjecttype/_search?typed_keys=true
- [1] 健康响应:节点:http://localhost:9200/ 获取:00:00:00.0620000
请求:
- [1] Healthy Response: Node: http://localhost:9200/ Took: 00:00:00.0620000
Request:
我的 POCO 课程:
My POCO Classes:
public class ComponentTypES
{
public string ComponentID { get; set; }
public string Componentname { get; set; }
public string Summary { get; set; }
}
public class ProjectTypES
{
public string ProjectID { get; set; }
public string Projectname { get; set; }
public string Summary { get; set; }
public string Description { get; set; }
}
样本数据:
PUT componenttypeindex/Componenttype/5342e739-1635-4021-baf2-55e25b95b8ec
{
"ComponentID":"5342e739-1635-4021-baf2-55e25b95b8ec",
"Componentname":"TestComponent1",
"Summary":"this is summary of test component1"
}
PUT componenttypeindex/Componenttype/90781386-8065-11e9-bc42-526af7764f64
{
"ComponentID":"90781386-8065-11e9-bc42-526af7764f64",
"Componentname":"TestComponent2",
"Summary":"this is summary of test component3"
}
PUT componenttypeindex/Componenttype/19871386-8065-11e9-bc42-526af7764f64
{
"ComponentID":"19871386-8065-11e9-bc42-526af7764f64",
"Componentname":"some xyz component test",
"Summary":"this is summary test of test xyz"
}
PUT projecttypeindex/Projecttype/5342e739-2019-4021-baf2-55e25b95b8ec
{
"ProjectID":"5342e739-2019-4021-baf2-55e25b95b8ec",
"Projectname":"Test Project1",
"Summary":"summary of Test Project1",
"Description":"Description of TestProject1"
}
PUT projecttypeindex/Projecttype/5342f739-2019-4021-baf2-55e25b95b8ba
{
"ProjectID":"5342f739-2019-4021-baf2-55e25b95b8ba",
"Projectname":"Test Project2",
"Summary":"summary of Test Project2",
"Description":"Description of TestProject1"
}
PUT projecttypeindex/Projecttype/6342f739-2020-4021-baf2-55e25b95b8ac
{
"ProjectID":"6342f739-2020-4021-baf2-55e25b95b8ac",
"Projectname":"some PQRS project",
"Summary":"summary of PQRS Project",
"Description":"Description of PQORS Project1"
}
推荐答案
您的示例中有很多多余的信息,这使得使用起来很棘手,这增加了希望提供帮助的人所需的努力的障碍.我是否建议您将示例缩减为最小、简洁但完整的示例,以展示您将来面临的问题;它真的有助于更快地找到问题的症结!
There's a lot of superfluous information in your example that makes it tricky to work with, which raises the barrier of effort required by someone wishing to help. Could I suggest that you reduce an example down to the smallest, succinct but complete example that demonstrates the problem you are facing in future; it'll really help in getting to the crux of the issue quicker!
我认为根本问题是索引映射中字段内的属性大小写与NEST默认发送的属性大小写不同,因此嵌套的must
子句在由于字段大小写不同,NEST 生成的 bool
查询的 should
子句永远不会被任何文档匹配.
I think the fundamental issue is that the casing of properties within the fields in the index mappings, and the casing of properties that NEST will send by default are different, so the nested must
clauses within the should
clause of the bool
query that is generated by NEST will never be matched by any documents because of the field casing difference.
NEST默认情况下,骆驼案例属性名称,但您示例中的索引映射和文档中的字段都是 pascal 大小写的,因此 NEST 生成的字段名称将与映射中的字段名称不匹配.您可以使用 ConnectionSettings
上的 DefaultFieldNameInferrer(Func
方法轻松更改 NEST 的字段大小写行为.仅返回传递的字符串值的委托将保留字段名称,如它们在 POCO 上一样.
NEST by default camel cases property names, but the fields in the index mappings and documents in your example are all pascal cased, so the field names generated by NEST will not match those within the mapping. You can easily change NEST's field casing behaviour by using the DefaultFieldNameInferrer(Func<string, string>)
method on ConnectionSettings
. A delegate that simply returns the string value passed will leave field names as they are on the POCOs.
这是一个完整但简洁的工作示例
Here's a complete but succinct, working example
private static void Main()
{
const string componentIndex = "componenttypeindex";
const string projectIndex = "projecttypeindex";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultIndex(componentIndex)
.DefaultMappingFor<ComponentTypES>(i => i.IndexName(componentIndex).TypeName("Componenttype").IdProperty(f => f.ComponentID))
.DefaultMappingFor<ProjectTypES>(j => j.IndexName(projectIndex).TypeName("Projecttype").IdProperty(f => f.ProjectID))
.DefaultFieldNameInferrer(f => f)
.DefaultTypeName("_doc")
.DisableDirectStreaming()
.PrettyJson()
.OnRequestCompleted(callDetails =>
{
if (callDetails.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{callDetails.HttpMethod} {callDetails.Uri} \n" +
$"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
}
Console.WriteLine();
if (callDetails.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
});
var client = new ElasticClient(settings);
foreach (var index in new[] { componentIndex, projectIndex })
{
if (client.IndexExists(index).Exists)
client.DeleteIndex(index);
client.CreateIndex(index, c => c
.Mappings(m => {
if (index == projectIndex)
return m.Map<ProjectTypES>(mm => mm.AutoMap());
else
return m.Map<ComponentTypES>(mm => mm.AutoMap());
})
);
}
client.Bulk(b => b
.IndexMany(new [] {
new ComponentTypES
{
ComponentID = "5342e739-1635-4021-baf2-55e25b95b8ec",
Componentname = "TestComponent1",
Summary = "this is summary of test component1"
},
new ComponentTypES
{
ComponentID = "90781386-8065-11e9-bc42-526af7764f64",
Componentname = "TestComponent2",
Summary = "this is summary of test component3"
},
new ComponentTypES
{
ComponentID = "19871386-8065-11e9-bc42-526af7764f64",
Componentname = "some xyz component test",
Summary = "this is summary test of test xyz"
},
})
.IndexMany(new [] {
new ProjectTypES
{
ProjectID = "5342e739-2019-4021-baf2-55e25b95b8ec",
Projectname = "Test Project1",
Summary = "summary of Test Project1",
Description = "Description of TestProject1"
},
new ProjectTypES
{
ProjectID = "5342f739-2019-4021-baf2-55e25b95b8ba",
Projectname = "Test Project2",
Summary = "summary of Test Project2",
Description = "Description of TestProject1"
},
new ProjectTypES
{
ProjectID = "6342f739-2020-4021-baf2-55e25b95b8ac",
Projectname = "some PQRS project",
Summary = "summary of PQRS Project",
Description = "Description of PQORS Project1"
},
})
.Refresh(Refresh.WaitFor)
);
var query = "test";
var response = client.Search<object>(s => s
.Index(Indices.Index(typeof(ComponentTypES)).And(typeof(ProjectTypES)))
.Type(Types.Type(typeof(ComponentTypES), typeof(ProjectTypES)))
.Query(q =>
(q
.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<ComponentTypES>(ff => ff.Componentname))
.Field(Infer.Field<ComponentTypES>(ff => ff.Summary, 1.1))
)
.Operator(Operator.Or)
.Query(query)
) && +q
.Term("_index", componentIndex)
) ||
(q
.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<ProjectTypES>(ff => ff.Projectname))
.Field(Infer.Field<ProjectTypES>(ff => ff.Summary, 0.3))
)
.Operator(Operator.Or)
.Query(query)
) && +q
.Term("_index", projectIndex)
)
)
);
}
public class ComponentTypES
{
public string ComponentID { get; set; }
public string Componentname { get; set; }
public string Summary { get; set; }
}
public class ProjectTypES
{
public string ProjectID { get; set; }
public string Projectname { get; set; }
public string Summary { get; set; }
public string Description { get; set; }
}
搜索的结果 JSON 查询是
The resulting JSON query for the search is
POST http://localhost:9200/componenttypeindex%2Cprojecttypeindex/Componenttype%2CProjecttype/_search?pretty=true&typed_keys=true
{
"query": {
"bool": {
"should": [
{
"bool": {
"filter": [
{
"term": {
"_index": {
"value": "componenttypeindex"
}
}
}
],
"must": [
{
"multi_match": {
"fields": [
"Componentname",
"Summary^1.1"
],
"operator": "or",
"query": "test"
}
}
]
}
},
{
"bool": {
"filter": [
{
"term": {
"_index": {
"value": "projecttypeindex"
}
}
}
],
"must": [
{
"multi_match": {
"fields": [
"Projectname",
"Summary^0.3"
],
"operator": "or",
"query": "test"
}
}
]
}
}
]
}
}
}
返回 5 个结果
{
"took" : 53,
"timed_out" : false,
"_shards" : {
"total" : 10,
"successful" : 10,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 5,
"max_score" : 0.7549128,
"hits" : [
{
"_index" : "projecttypeindex",
"_type" : "Projecttype",
"_id" : "5342e739-2019-4021-baf2-55e25b95b8ec",
"_score" : 0.7549128,
"_source" : {
"ProjectID" : "5342e739-2019-4021-baf2-55e25b95b8ec",
"Projectname" : "Test Project1",
"Summary" : "summary of Test Project1",
"Description" : "Description of TestProject1"
}
},
{
"_index" : "componenttypeindex",
"_type" : "Componenttype",
"_id" : "19871386-8065-11e9-bc42-526af7764f64",
"_score" : 0.5565415,
"_source" : {
"ComponentID" : "19871386-8065-11e9-bc42-526af7764f64",
"Componentname" : "some xyz component test",
"Summary" : "this is summary test of test xyz"
}
},
{
"_index" : "componenttypeindex",
"_type" : "Componenttype",
"_id" : "5342e739-1635-4021-baf2-55e25b95b8ec",
"_score" : 0.3164503,
"_source" : {
"ComponentID" : "5342e739-1635-4021-baf2-55e25b95b8ec",
"Componentname" : "TestComponent1",
"Summary" : "this is summary of test component1"
}
},
{
"_index" : "projecttypeindex",
"_type" : "Projecttype",
"_id" : "5342f739-2019-4021-baf2-55e25b95b8ba",
"_score" : 0.2876821,
"_source" : {
"ProjectID" : "5342f739-2019-4021-baf2-55e25b95b8ba",
"Projectname" : "Test Project2",
"Summary" : "summary of Test Project2",
"Description" : "Description of TestProject1"
}
},
{
"_index" : "componenttypeindex",
"_type" : "Componenttype",
"_id" : "90781386-8065-11e9-bc42-526af7764f64",
"_score" : 0.20706992,
"_source" : {
"ComponentID" : "90781386-8065-11e9-bc42-526af7764f64",
"Componentname" : "TestComponent2",
"Summary" : "this is summary of test component3"
}
}
]
}
}
这篇关于使用 NEST C# 在弹性搜索中使用多个索引进行全文搜索的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!