#elasticsearch #nest
#elasticsearch #гнездо
Вопрос:
Я хочу выполнить запрос Elasticsearch, который объединяет два подзапроса (И operator ), каждый из которых выполняет поиск в разных полях (ИЛИ operator ).
Например, если я передаю параметр «name», он выполняет поиск только в полях имени (firstname lastname), если я передаю параметр «contact», он выполняет поиск в полях контактов (ContactEmail ContactTelephone).
Приведенный ниже код возвращает :
- Все результаты, если имя равно нулю, но указан контакт (должен возвращать только правую часть)
- Все результаты, если контакт равен нулю, но указано имя (должно возвращать только левую часть)
- результаты объединения (ИЛИ оператор), если указаны значения name и contact (должны возвращать left пересекаться с right)
searchQuery = searchQuery
.MinScore(minScore)
.Query(qu => qu
.Bool(b => b
.Must(m => m
.MultiMatch(mm=> mm
.Fields(fs=> fs
.Field(f => f.Firstname)
.Field(f => f.Lastname)
)
.Query(name)
.Operator(Operator.Or)
)
)
.Must(m => m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.ContactEmail)
.Field(f => f.ContactTelephone)
)
.Query(contact)
.Operator(Operator.Or)
)
)
)
);
Я использую Must
, потому что мне нужна соответствующая оценка.
Я думаю, что есть 2 проблемы: применение И вместо ИЛИ и игнорирование подзапроса, если критерий пуст. Есть идеи?
Ответ №1:
Два запроса в предложениях must должны быть частью одного и того же .Must()
вызова.
Учитывая следующий POCO
public class Person
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public string ContactEmail {get;set;}
public string ContactTelephone {get;set;}
}
Запрос должен выглядеть следующим образом
var client = new ElasticClient(settings);
var minScore = 2;
string name = "name";
string contact = "contact";
var response = client.Search<Person>(s => s
.MinScore(minScore)
.Query(qu => qu
.Bool(b => b
.Must(m => m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.Firstname)
.Field(f => f.Lastname)
)
.Query(name)
.Operator(Operator.Or)
), m => m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.ContactEmail)
.Field(f => f.ContactTelephone)
)
.Query(contact)
.Operator(Operator.Or)
)
)
)
)
);
что приводит к следующему
{
"min_score": 2.0,
"query": {
"bool": {
"must": [
{
"multi_match": {
"fields": [
"contactEmail",
"contactTelephone"
],
"operator": "or",
"query": "contact"
}
}
]
}
}
}
Если либо name
или contact
есть null
, этот запрос будет опущен. Например, установка name
в null
string name = null;
var response = client.Search<Person>(s => s
.MinScore(minScore)
.Query(qu => qu
.Bool(b => b
.Must(m => m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.Firstname)
.Field(f => f.Lastname)
)
.Query(name)
.Operator(Operator.Or)
), m => m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.ContactEmail)
.Field(f => f.ContactTelephone)
)
.Query(contact)
.Operator(Operator.Or)
)
)
)
)
);
выдает
{
"min_score": 2.0,
"query": {
"bool": {
"must": [
{
"multi_match": {
"fields": [
"contactEmail",
"contactTelephone"
],
"operator": "or",
"query": "contact"
}
}
]
}
}
}
Это использует преимущества клиентской функции, называемой запросами без условий — конкретный запрос считается не имеющим условий, если компонент запроса пуст, когда он не должен быть, для формирования полного запроса. Например, для multi_match
запроса он считается не имеющим условий, если Query
null
Цель запросов без условий заключается в том, что это упрощает написание более сложных запросов, а поведение можно обойти, указав Verbatim()
в запросе. Однако, поскольку они противоречат принципу наименьшего удивления, есть намерение удалить их в будущем. Для выполнения одного и того же запроса, не полагаясь на поведение без условий
var response = client.Search<Person>(s => s
.MinScore(minScore)
.Query(qu => qu
.Bool(b => b
.Must(m =>
{
if (name == null)
return m;
return m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.Firstname)
.Field(f => f.Lastname)
)
.Query(name)
.Operator(Operator.Or)
);
}, m =>
{
if (contact == null)
return m;
return m
.MultiMatch(mm => mm
.Fields(fs => fs
.Field(f => f.ContactEmail)
.Field(f => f.ContactTelephone)
)
.Query(contact)
.Operator(Operator.Or)
);
}
)
)
)
);
Комментарии:
1. Спасибо @Russ Cam за такой качественный ответ!
2. Не беспокойтесь! Надеюсь, это поможет