代码之家  ›  专栏  ›  技术社区  ›  randow_user_1234

在ElasticSearch 6.6和Nest 6.6中具有排序和分页变量的搜索模板

  •  0
  • randow_user_1234  · 技术社区  · 5 年前

    所有的, 我试图调用在ES6.6中定义的搜索模板。模板包含分页变量(来自和大小)和我在数组中传递的电子邮件。这还具有使用自定义脚本逻辑进行排序的功能。当我在Kibana中运行这个程序时,我看不到分页和排序不起作用。如果能帮上忙,我将不胜感激。请参阅下面的详细信息。我使用索引别名搜索两个索引。

    人员索引和来宾索引的映射是相同的(只是为了简化示例)

    索引映射

    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"
        }
          }
        }
      }
    }
    

    搜索模板定义

    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}}
                }
              }
            }
          }
        }
    """
      }
    }
    

    使用搜索模板搜索

    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调用SearchTemplate

    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中删除from、size和sort逻辑时,它会起作用。
    2. 似乎我把sort和from/size变量放错了地方?

    我在这里找到了一个类似的帖子 https://discuss.elastic.co/t/c-nest-5-search-with-template/104074/2 但是看起来getsearchtemplate和putsearchtemplate已经在nest 6.x上停止使用了。

    是否可以使用搜索模板完成此操作?我们使用一些非常复杂的嵌套查询,并且正在远离嵌套并使用搜索模板。

    2 回复  |  直到 5 年前
        1
  •  1
  •   Russ Cam    5 年前

    有几个问题

    1. 索引模板定义 "email" 字段映射两次
    2. 索引模板集 "dynamic" 错误,但不包含 "type" 字段映射,因此脚本排序将失败
    3. 整个搜索请求需要在 "source" 对于Put脚本API调用

    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"
            ]
          }
        ]
      }
    }
    
        2
  •  0
  •   randow_user_1234    5 年前

    添加正确的搜索模板(在“下移动分页和排序” 来源 正如RussCam指出的那样),以防将来有人需要它。

    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}}
                }
              }
            }
          }
        }
    """
      }
    }