SearchTemplate с переменными сортировки и подкачки в Elasticsearch 6.6 и NEST 6.6 - PullRequest
0 голосов
/ 11 февраля 2019

Все, я пытаюсь вызвать шаблон поиска, определенный в ES 6.6.Шаблон имеет переменные подкачки (от и размер) и электронные письма, которые я передаю в массиве.Это также имеет сортировку с пользовательской логикой сценария.Когда я запускаю это в кибане, я не вижу, что подкачка и сортировка не работают.Я был бы признателен за любую помощь в получении этого на работу.Пожалуйста, смотрите детали ниже.Есть два индекса, которые я ищу, используя псевдоним индекса.

Отображения для индексов человека и гостя одинаковы (только для упрощения примера)

Отображение индекса

PUT _template/person_guest_template
{
  "order": 0,
  "index_patterns": ["person*","guest*"],
  "settings": {
    "index": {
      "analysis": {
        "filter": {
          "autoComplete_filter": {
            "type": "edge_ngram",
            "min_gram": "2",
            "max_gram": "20"
          }
        },
        "analyzer": {
          "autoComplete": {
            "filter": ["lowercase", "asciifolding","autoComplete_filter"],
            "type": "custom",
            "tokenizer": "whitespace"
          },
          "default": {
            "filter": ["lowercase", "asciifolding"],
            "type": "custom",
            "tokenizer": "whitespace"
          }
        }
      },
      "number_of_shards": "3",
      "number_of_replicas": "1"
    }
  },
  "mappings": {
    "_doc": {
      "dynamic": false,
      "properties": {
        "firstName": {
          "type": "keyword",
          "fields": {
            "search": {
              "type": "text",
              "analyzer": "autoComplete",
              "search_analyzer": "default"
            }
          }
        },
        "lastName": {
          "type": "keyword",
          "fields": {
            "search": {
              "type": "text",
              "analyzer": "autoComplete",
              "search_analyzer": "default"
            }
          }
        },
        "email": {
          "type": "keyword"
        },"email": {
      "type": "keyword"
    }
      }
    }
  }
}

Определение SearchTemplate

POST _scripts/guest_person_by_email
{
  "script": {
    "from": "{{from}}{{^from}}0{{/from}}",
    "size": "{{size}}{{^size}}5{{/size}}",
    "sort": [
      {
        "_script": {
          "order": "asc",
          "type": "number",
          "script": "return (doc['type'].value == 'person')? 0 : 1;"
        }
      },
      {
        "firstName": {
          "order": "asc"
        }
      },
      {
        "lastName": {
          "order": "asc"
        }
      }
    ],
    "lang": "mustache",
    "source": """
    {
      "query":{
        "bool":{
          "filter":{
            "terms":{
              "email":
              {{#toJson}}emails{{/toJson}}
            }
          }
        }
      }
    }
"""
  }
}

Поиск с использованием SearchTemplate

GET guest-person/_search/template
{
  "id":"guest_person_by_email",
  "params": {
    "emails":["rennishj@test.com"]
  }
}

Пример данных

PUT person/_doc/1
{
  "firstName": "Rennish",
  "lastName": "Joseph",
  "email": [
    "rennishj@test.com"
  ],
  "type":"person"
}

Вызов поисковой таблицы с использованием NEST 6.6

List<string> emails = new List<string>(){"rennishj@test.com"};
var searchResponse = client.SearchTemplate<object>(st => st
    .Index("guest-person")
    .Id("guest_person_by_email")
    .Params(p => p
        .Add("emails", emails.ToArray())
        .Add("from", 0)     
        .Add("size", 50)
    )
);

Наблюдения

  1. Когда я удаляю из,логика размера и сортировки из searchtemplate, она работает
  2. Похоже, я помещаю переменные sort и from / size в неправильное место?

Я нашел похожий пост здесь https://discuss.elastic.co/t/c-nest-5-search-with-template/104074/2 но похоже, что GetSearchTemplate и PutSearchTemplate более не поддерживаются в NEST 6.x

Можно ли это сделать с помощью поисковых шаблонов?Мы используем несколько очень сложных запросов NEST, отходим от NEST и используем шаблоны поиска.

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Добавление правильного SearchTemplate (перемещение страниц и сортировка в « source », как указал Расс Кэм) на случай, если кому-то понадобится в будущем.

POST _scripts/guest_person_by_email
{
  "script": {    
    "lang": "mustache",
    "source": """
     {
       "from": "{{from}}{{^from}}0{{/from}}",
       "size": "{{size}}{{^size}}5{{/size}}",
      "sort": [
      {
        "_script": {
          "order": "asc",
          "type": "number",
          "script": "return (doc['type'].value == 'person')? 0 : 1;"
        }
      },
      {
        "firstName": {
          "order": "asc"
        }
      },
      {
        "lastName": {
          "order": "asc"
        }
      }
    ],
      "query":{
        "bool":{
          "filter":{
            "terms":{
              "email":
              {{#toJson}}emails{{/toJson}}
            }
          }
        }
      }
    }
"""
  }
}
0 голосов
/ 11 февраля 2019

Существует несколько проблем

  1. шаблон индекса определяет "email" отображение поля дважды
  2. шаблон индекса устанавливает "dynamic" в значение false, но не содержит "type" отображение поля,так что сортировка сценария не удастся
  3. весь запрос на поиск должен быть определен в "source" для вызова API Put Script

NEST может помочь в построении правильных поисковых запросов и использованииони служат основой для шаблона поиска, помимо множества других причин использования клиента, таких как запросы циклического перебора, автоматическое переключение при сбое и повторные попытки и т. д.

Вот полный пример

private static void Main()
{
    var defaultIndex = "person";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    var settings = new ConnectionSettings(pool)
        .DefaultIndex(defaultIndex)
        .DefaultTypeName("_doc");

    var client = new ElasticClient(settings);

    // WARNING: This deletes the index to make this code repeatable.
    // You probably want to remove this if copying verbatim
    if (client.IndexExists(defaultIndex).Exists)
        client.DeleteIndex(defaultIndex);

    var indexTemplateResponse = client.LowLevel.IndicesPutTemplateForAll<PutIndexTemplateResponse>(
        "person_guest_template",
        @"{
          ""order"": 0,
          ""index_patterns"": [""person*"",""guest*""],
          ""settings"": {
            ""index"": {
              ""analysis"": {
                ""filter"": {
                  ""autoComplete_filter"": {
                    ""type"": ""edge_ngram"",
                    ""min_gram"": ""2"",
                    ""max_gram"": ""20""
                  }
                },
                ""analyzer"": {
                  ""autoComplete"": {
                    ""filter"": [""lowercase"", ""asciifolding"",""autoComplete_filter""],
                    ""type"": ""custom"",
                    ""tokenizer"": ""whitespace""
                  },
                  ""default"": {
                    ""filter"": [""lowercase"", ""asciifolding""],
                    ""type"": ""custom"",
                    ""tokenizer"": ""whitespace""
                  }
                }
              },
              ""number_of_shards"": ""3"",
              ""number_of_replicas"": ""1""
            }
          },
          ""mappings"": {
            ""_doc"": {
              ""dynamic"": false,
              ""properties"": {
                ""firstName"": {
                  ""type"": ""keyword"",
                  ""fields"": {
                    ""search"": {
                      ""type"": ""text"",
                      ""analyzer"": ""autoComplete"",
                      ""search_analyzer"": ""default""
                    }
                  }
                },
                ""lastName"": {
                  ""type"": ""keyword"",
                  ""fields"": {
                    ""search"": {
                      ""type"": ""text"",
                      ""analyzer"": ""autoComplete"",
                      ""search_analyzer"": ""default""
                    }
                  }
                },
                ""email"": {
                  ""type"": ""keyword""
                },
                ""type"": {
                  ""type"": ""keyword""
                }
              }
            }
          }
        }");

    // build a prototype search request     
    var searchRequest = new SearchRequest
    {
        From = 0,
        Size = 0,
        Sort = new List<ISort> 
        {
            new ScriptSort
            {
                Order = Nest.SortOrder.Ascending,
                Type = "number",
                Script = new InlineScript("return (doc['type'].value == 'person')? 0 : 1;")
            },
            new SortField
            {
                Field = "firstName",
                Order = Nest.SortOrder.Ascending
            },
            new SortField
            {
                Field = "lastName",
                Order = Nest.SortOrder.Ascending
            }
        },
        Query = new BoolQuery
        {
            Filter = new QueryContainer[] 
            {
                new TermsQuery
                {
                    Field = "email",
                    Terms = new[] { "emails" }
                }
            }
        }
    };

    var json = client.RequestResponseSerializer.SerializeToString(searchRequest);
    // create template from prototype search request
    var jObject = JsonConvert.DeserializeObject<JObject>(json); 
    jObject["from"] = "{{from}}{{^from}}0{{/from}}";
    jObject["size"] = "{{size}}{{^size}}5{{/size}}";    
    json = jObject.ToString(Newtonsoft.Json.Formatting.None);
    // below is invalid JSON, so can only be constructed with replacement
    json = json.Replace("[\"emails\"]", "{{#toJson}}emails{{/toJson}}");

    // add search template
    var putScriptResponse = client.PutScript("guest_person_by_email", s => s
        .Script(sc => sc
            .Lang(ScriptLang.Mustache)
            .Source(json)
        )
    );

    var person = new Person
    {
        FirstName = "Rennish",
        LastName = "Joseph",
        Email = new[] { "rennishj@test.com" }
    };

    // index document
    var indexResponse = client.Index(person, i => i.Id(1).Refresh(Refresh.WaitFor));

    // search
    var searchResponse = client.SearchTemplate<Person>(s => s
        .Id("guest_person_by_email")
        .Params(p => p
            .Add("emails", person.Email)
            .Add("from", 0)
            .Add("size", 50)
        )
    );
}

public class Person 
{
    public string FirstName {get;set;}
    public string LastName { get; set; }
    public string[] Email {get;set;}
    public string Type {get; set;} = "person";
}

Результат запроса шаблона поиска:

{
  "took" : 47,
  "timed_out" : false,
  "_shards" : {
    "total" : 3,
    "successful" : 3,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "person",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "firstName" : "Rennish",
          "lastName" : "Joseph",
          "email" : [
            "rennishj@test.com"
          ],
          "type" : "person"
        },
        "sort" : [
          0.0,
          "Rennish",
          "Joseph"
        ]
      }
    ]
  }
}
...