社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
私信  •  关注

Russ Cam

Russ Cam 最近创建的主题
Russ Cam 最近回复了
6 年前
回复了 Russ Cam 创建的主题 » 如何在elasticsearch中添加文档时引用多个字段

可以使用update API更新单个字段

var client = new ElasticClient();

var documentId = 1;

var partial = new 
{
    Description = "This is some description"
};

var updateResponse = client.Update<Document, object>(documentId, u => u
    .Index("your_index")
    .Doc(partial)
);

这个 .Index() Document 键入。要更新的文档是用部分文档建模的,因为使用 将导致为值类型发送默认值,如 DocumentDate DocumentType_Id

doc.Description.en=“这是一些描述”;

不可能这样做,因为这不是 multi-fields 工作。对于多个字段,可以通过多种不同的方式分析单个文档字段输入,以满足不同的搜索需求。在你的例子中, Description 财产价值将通过4种不同的方式进行分析:

  1. 用标准分析仪 text 映射
  2. 由英语分析器和 .en 多场映射
  3. 通过Nofa波斯语分析器 .fa 多场映射
  4. .fr 多场映射

"description" 字段,当您检索 _source 对于文档(如果 存储,默认情况下为)。

如果要将这些字段建模为文档上的单独字段,可以引入 具有必需属性的类型

public class Description
{
    public string Standard { get;set; }
    public string English { get;set; }
    public string NoFaPersian{ get;set; }
    public string French{ get;set; }
}

然后将其索引为 object 类型映射,为每个

public class Document
{
    public string BaseUniqueID { get; set; }
    public int? Weight { get; set; }
    public DateTime DocumentDate { get; set; }
    public Description Description { get; set; }
    public int DocumentType_Id { get; set; }
}

var indexResponse = client.CreateIndex("your_index", c => c
    .Mappings(m => m
        .Map<Document>(mm => mm
            .AutoMap()
            .Properties(p => p
                .Object<Description>(o => o
                    .Name(n => n.Description)
                    .AutoMap()
                    .Properties(pp => pp
                        .Text(t => t.Name(n => n.Standard).Analyzer("standard"))
                        .Text(t => t.Name(n => n.English).Analyzer("english"))
                        .Text(t => t.Name(n => n.NoFaPersian).Analyzer("nofapersian"))
                        .Text(t => t.Name(n => n.French).Analyzer("french"))
                    )
                )
            )
        )
    )       
);

它生成以下创建索引请求

PUT http://localhost:9200/your_index?pretty=true 
{
  "mappings": {
    "document": {
      "properties": {
        "baseUniqueID": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        "weight": {
          "type": "integer"
        },
        "documentDate": {
          "type": "date"
        },
        "description": {
          "type": "object",
          "properties": {
            "standard": {
              "type": "text",
              "analyzer": "standard"
            },
            "english": {
              "type": "text",
              "analyzer": "english"
            },
            "noFaPersian": {
              "type": "text",
              "analyzer": "nofapersian"
            },
            "french": {
              "type": "text",
              "analyzer": "french"
            }
          }
        },
        "documentType_Id": {
          "type": "integer"
        }
      }
    }
  }
}
6 年前
回复了 Russ Cam 创建的主题 » 嵌套-当项为空时多匹配搜索所有文档-ElasticSearch 6.4

默认情况下,nest通过一个称为 Conditionless queries 是的。你可以

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

    var settings = new ConnectionSettings(pool, new InMemoryConnection())
        .DefaultIndex(defaultIndex)
        .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);

    var pageSize = 20;
    var currentPageIndex = 0;  
    string search = "foo";


    var searchResponse = client.Search<DocumentElasticModel>(s => s
        .Size(pageSize)
        .Skip(currentPageIndex * pageSize)
        .Sort(ss => ss
            .Descending(SortSpecialField.Score)
        )
        .Source(sf => sf
            .Includes(i => i
                .Fields(f => f.TopLevelMessage)
            )
        )
        .Query(q => q
            .Nested(c => c
                .Name("named_query")
                .Boost(1.1)
                .InnerHits(i => i.Explain())
                .Path(p => p.PerguntasRespostas)
                .Query(nq => nq
                    .MultiMatch(m => m
                        .Fields(f => f
                            .Field(ff => ff.PerguntasRespostas.First().Message)
                        ) 
                        .Query(search)
                    )
                )
                .IgnoreUnmapped()
            )
        )
    );
}


public class DocumentElasticModel 
{
    public string TopLevelMessage { get; set; }

    public IEnumerable<PerguntasRespostas> PerguntasRespostas {get;set;}
}

public class PerguntasRespostas
{
    public string Message { get; set; }  
}

这将发送以下查询

POST http://localhost:9200/documents/documentelasticmodel/_search
{
  "from": 0,
  "size": 20,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "_source": {
    "includes": [
      "topLevelMessage"
    ]
  },
  "query": {
    "nested": {
      "_name": "named_query",
      "boost": 1.1,
      "query": {
        "multi_match": {
          "query": "foo",
          "fields": [
            "perguntasRespostas.message"
          ]
        }
      },
      "path": "perguntasRespostas",
      "inner_hits": {
        "explain": true
      },
      "ignore_unmapped": true
    }
  }
}

现在,如果你改变 search string.Empty null ,你得到

POST http://localhost:9200/documents/documentelasticmodel/_search
{
  "from": 0,
  "size": 20,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "_source": {
    "includes": [
      "topLevelMessage"
    ]
  }
}

没有明确的 "query" 在请求中,这与 match_all 查询。

如果要重写嵌套中的无条件查询功能,可以将查询标记为 .Verbatim() Nest会按原样发送

var searchResponse = client.Search<DocumentElasticModel>(s => s
    .Size(pageSize)
    .Skip(currentPageIndex * pageSize)
    .Sort(ss => ss
        .Descending(SortSpecialField.Score)
    )
    .Source(sf => sf
        .Includes(i => i
            .Fields(f => f.TopLevelMessage)
        )
    )
    .Query(q => q
        .Nested(c => c
            .Verbatim() // <-- mark the nested query
            .Name("named_query")          
            .Boost(1.1)
            .InnerHits(i => i.Explain())
            .Path(p => p.PerguntasRespostas)
            .Query(nq => nq
                .MultiMatch(m => m
                    .Verbatim() // <-- mark the inner query
                    .Fields(f => f
                        .Field(ff => ff.PerguntasRespostas.First().Message)
                    ) 
                    .Query(search)
                )
            )
            .IgnoreUnmapped()
        )
    )
);

它发出

POST http://localhost:9200/documents/documentelasticmodel/_search
{
  "from": 0,
  "size": 20,
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ],
  "_source": {
    "includes": [
      "topLevelMessage"
    ]
  },
  "query": {
    "nested": {
      "_name": "named_query",
      "boost": 1.1,
      "query": {
        "multi_match": {
          "fields": [
            "perguntasRespostas.message"
          ]
        }
      },
      "path": "perguntasRespostas",
      "inner_hits": {
        "explain": true
      },
      "ignore_unmapped": true
    }
  }
}

您需要检查这是否是ElasticSearch接受的有效查询。

6 年前
回复了 Russ Cam 创建的主题 » 在ElasticSearch中对嵌套集合执行查询,嵌套在.NET Core中

你不需要表演 nested 查询以查询 Tags 字段,因为每个标记只是一个原始json值,即 string . 只是 terms 查询就足够了。

在哪里 嵌套的 需要查询的是 标签 是具有多个属性的poco,映射为 嵌套的 数据类型。

6 年前
回复了 Russ Cam 创建的主题 » 搜索查询elasticsearch with ngram始终返回0个结果

这个 ngram_analyzer 用于分析搜索请求的查询输入,但此分析器不用于分析 OriginalTitle 索引请求的输入。

您只需要将分析器配置为用于 原岩 索引文档时的字段,可以用 attribute mapping fluent mapping . 例如,fluent映射

var client = new ElasticClient();

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

var nGramFilters = new List<string> { "lowercase", "asciifolding", "nGram_filter" };

var resp = client.CreateIndex(defaultIndex, c => c
     .Mappings(m => m
        .Map<ElasticVideoMaterial>(mm => mm
            .AutoMap()
            .Properties(p => p
                .Text(t => t
                    .Name(n => n.OriginalTitle)
                    .Fields(f => f
                        .Keyword(k => k
                            .Name("keyword")
                            .IgnoreAbove(256)
                        )
                        .Text(tt => tt
                            .Name("ngram")
                            .Analyzer("ngram_analyzer")
                        )
                    )
                )
            )
        )
    )
    .Settings(s => s
        .Analysis(a => a
            .Analyzers(anz => anz
                .Custom("ngram_analyzer", cc => cc
                    .Filters(nGramFilters)
                    .Tokenizer("ngram_tokenizer")))
            .Tokenizers(tz => tz
                .NGram("ngram_tokenizer", td => td
                    .MinGram(3)
                    .MaxGram(3)
                    .TokenChars(TokenChar.Letter, TokenChar.Digit)
                )
            )
        )
    )
);

var searchResponse = client.Search<ElasticVideoMaterial>(i => i
    .Query(q => q
        .Match(m => m
            .Field(f => f.OriginalTitle.Suffix("ngram"))
            .Query("Hob")
        )
    )
);

这成立了 原岩 作为一个 multi-field 并创建一个称为 ngram 在下面 原岩 它将使用 ngram_分析仪 在此字段的索引时间和搜索时间。

15 年前
回复了 Russ Cam 创建的主题 » 组合框交互中的jquery live方法

试用使用 change onchange live() 方法。另外,如果我的内存正确地为我服务,您将需要jquery 1.4+来使用 live 对于change事件,因为代码仅在1.4+中实现,以处理 改变 事件。

为了将新选择的值与上一个选择的值进行比较,您可以考虑存储选定的值以供使用 $.data() -然后,可以将更改事件后的值与存储在$.cache(其中$.data()存储值)中的值进行比较,并执行必要的操作。您也可以使用闭包来实现它。

6 年前
回复了 Russ Cam 创建的主题 » ElasticSearch中是否有批量部分更新?

您可以使用批量API发送部分更新。下面是一个例子

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

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

    var client = new ElasticClient(settings);

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

    var docs = Enumerable.Range(1, 10).Select(i => new MyDocument(i) 
        {
            Message = $"message {i}"
        });

    // bulk index the documents   
    var bulkResponse = client.Bulk(b => b
        .IndexMany(docs)
        .Refresh(Refresh.WaitFor)
    );

    var searchResponse = client.Search<MyDocument>(s => s
        .Sort(so => so.Ascending("_id"))
    );

    // update the documents
    bulkResponse = client.Bulk(b => b
        .UpdateMany<MyDocument, object>(docs, (bu, doc) => 
        {
            if (doc.Id % 3 == 0)
            {
                // use script to update
                bu.Id(doc.Id).Script(s => s
                    .Source("ctx._source.message = 'message ' + (Integer.parseInt(ctx._id) * 2);")
                );
            }
            else if (doc.Id % 2 == 0)
            {
                // use partial document to update
                bu.Id(doc.Id).Doc(new { message = "updated message" });
            }
            else
            {
                // send the original document to update
                bu.Doc(doc);
            }

            return bu;
        })
        .Refresh(Refresh.WaitFor)
    );

    searchResponse = client.Search<MyDocument>(s => s
        .Sort(so => so.Ascending("_id"))
    );    
}


public class MyDocument 
{
    public MyDocument(int id) => Id = id;

    public int Id { get; set; }  

    public string Message { get; set; }
}

最终搜索响应返回

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 10,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "id" : 1,
          "message" : "message 1"
        },
        "sort" : [
          "1"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "10",
        "_score" : null,
        "_source" : {
          "id" : 10,
          "message" : "updated message"
        },
        "sort" : [
          "10"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "id" : 2,
          "message" : "updated message"
        },
        "sort" : [
          "2"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "3",
        "_score" : null,
        "_source" : {
          "id" : 3,
          "message" : "message 6"
        },
        "sort" : [
          "3"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "4",
        "_score" : null,
        "_source" : {
          "id" : 4,
          "message" : "updated message"
        },
        "sort" : [
          "4"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "5",
        "_score" : null,
        "_source" : {
          "id" : 5,
          "message" : "message 5"
        },
        "sort" : [
          "5"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "6",
        "_score" : null,
        "_source" : {
          "id" : 6,
          "message" : "message 12"
        },
        "sort" : [
          "6"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "7",
        "_score" : null,
        "_source" : {
          "id" : 7,
          "message" : "message 7"
        },
        "sort" : [
          "7"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "8",
        "_score" : null,
        "_source" : {
          "id" : 8,
          "message" : "updated message"
        },
        "sort" : [
          "8"
        ]
      },
      {
        "_index" : "documents",
        "_type" : "mydocument",
        "_id" : "9",
        "_score" : null,
        "_source" : {
          "id" : 9,
          "message" : "message 18"
        },
        "sort" : [
          "9"
        ]
      }
    ]
  }
}

注意源文档已更新

  1. 带有 _id 可被3整除已使用脚本更新更新文档
  2. 文档 圣婴 可被2除尽的部分更新了文档。
  3. 其余文档已通过传递原始文档进行了更新;这将导致 noop 在批量响应中。
15 年前
回复了 Russ Cam 创建的主题 » 将javascript转换为jquery

转换为更简洁的javascript?

var results = xvotesString[htmlid].split('~'),
    elem = function elem(prefix) {
       return document.getElementById(prefix + htmlid);
    }
if(var t3 = elem('xvote-')) 
    t3.style.width = results[0] + 'px';
if(var t4 = elem('mnma-'))
    t4.innerHTML = results[1];
if(var t5 = elem('mnma-'))
    t5.innerHTML = results[2];
if(var t6 = elem('mnmc-'))
    t6.style.display='none';
if(t6 = elem('mnmd-'))
    t6.style.display='block';
if(var t7 = elem('xvotes-'))
    t7.className += ' star-rating-noh';  
14 年前
回复了 Russ Cam 创建的主题 » jquery数组和jquery对象在技术上有什么区别?

第一个是正确的,第二个将失败,因为没有定义回调函数。如果定义了回调函数,并且click事件处理程序应用于中回调内部的每个迭代元素 .each() 然后两者在功能上是相似的。然而, each 调用实际上是多余的,因为jquery命令/方法是 通常地 应用于jquery对象中所有匹配的元素(有某些方法,例如 . val() 这不是,但他们是例外。这是通过内部应用 () :)

jquery对象是具有类似数组的属性的对象;所有匹配的元素都是对象的索引属性,即。

<p>Hello</p><World</p>

$('p'); // is an object { selector: 'p', O: [DOM Element], 1: [DOM Element], ... }

在哪里? [DOM Element] 表示对DOM中与选择器匹配的htmlelement的引用。 类似于数组的优点是它使得对对象执行数组操作非常简单。

6 年前
回复了 Russ Cam 创建的主题 » 如何使用ElasticSearch筛选查询结果

您要寻找的是将多个查询组合在一起的方法:

  1. 查询搜索词
  2. 查询 isGroup
  3. 查询 isUser
  4. 查询 organizationId

并使用这些组合执行搜索。这是类似 bool query 进来。给出以下POCO

public class UserGroupDocument 
{
    public string Name { get; set; }
    public bool IsGroup { get; set; }
    public bool IsUser { get; set; }
    public string OrganizationId { get; set; }
}

我们可以从

private static void Main()
{
    var defaultIndex = "default-index";
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); 
    var settings = new ConnectionSettings(pool)
        .DefaultIndex(defaultIndex);

    var client = new ElasticClient(settings);

    var isUser = true;
    var isGroup = true;
    var organizationId = "organizationId";

    var searchResponse = client.Search<UserGroupDocument>(x => x
        .Index(defaultIndex)
        .Query(q => q
            .Bool(b => b
                .Must(mu => mu
                    .QueryString(mmp => mmp
                        .Query("some admin")
                        .Fields(f => f
                            .Field(ff => ff.Name)
                        )
                    )
                )
                .Filter(fi => 
                    {
                        if (isUser)
                        {
                            return fi
                                .Term(f => f.IsUser, true);
                        }

                        return null;
                    }, fi =>
                    {
                        if (isGroup)
                        {
                            return fi
                                .Term(f => f.IsGroup, true);
                        }

                        return null;
                    }, fi => fi
                    .Term(f => f.OrganizationId, organizationId)
                )
            )
        )
    );
}

这将生成以下查询

POST http://localhost:9200/default-index/usergroupdocument/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "isUser": {
              "value": true
            }
          }
        },
        {
          "term": {
            "isGroup": {
              "value": true
            }
          }
        },
        {
          "term": {
            "organizationId": {
              "value": "organizationId"
            }
          }
        }
      ],
      "must": [
        {
          "query_string": {
            "fields": [
              "name"
            ],
            "query": "some admin"
          }
        }
      ]
    }
  }
}

如果

  • 伊塞尔 false , the term 查询筛选器 伊塞尔 字段将不包括在搜索查询中
  • IS-群 , the 学期 查询筛选器 IS-群 字段将不包括在搜索查询中
  • 组织ID null 或空字符串, 学期 查询筛选器 组织ID 不会包含在搜索查询中。

现在,我们可以走得更远 IS-群 伊塞尔 可空布尔值( bool? )然后,当其中一个值为 无效的 ,各自的 学期 发送到ElasticSearch的搜索查询中将不包含查询筛选器。这利用了一个称为 无条件的 Nest中的查询,旨在使编写更复杂的查询更容易。此外,我们可以使用 operator overloading on queries 使书写更容易 布尔 查询。这意味着我们可以将查询细化到

bool? isUser = true;
bool? isGroup = true;
var organizationId = "organizationId";

var searchResponse = client.Search<UserGroupDocument>(x => x
    .Index(defaultIndex)
    .Query(q => q
        .QueryString(mmp => mmp
            .Query("some admin")
            .Fields(f => f
                .Field(ff => ff.Name)
            )
        ) && +q
        .Term(f => f.IsUser, isUser) && +q
        .Term(f => f.IsGroup, isGroup) && +q
        .Term(f => f.OrganizationId, organizationId)
    )
);
6 年前
回复了 Russ Cam 创建的主题 » ElasticSearch嵌套-GroupBy,然后OrderBy

假设一个模型

public class Student 
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Grade { get; set; }
}

下面将按学生姓名分组,然后按年级降序排列每组中的前x个点击数。

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

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

    var client = new ElasticClient(settings);

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

    var createIndexResponse = client.CreateIndex(defaultIndex, c => c
        .Settings(s => s
            .NumberOfShards(1)
            .NumberOfReplicas(0)
        )
        .Mappings(m => m
            .Map<Student>(mm => mm
                .AutoMap()
            )
        )
    );

    var students = Enumerable.Range(1, 20).Select(i =>
        new Student 
        {
            Id = i,
            Name = i % 2 == 0 ? "Foo" : "Bar",
            Grade = i
        }
    );

    var bulkResponse = client.Bulk(b => b
        .IndexMany(students)
        .Refresh(Refresh.WaitFor) // refresh, so that documents indexed are available to search immediately
    );

    var topX = 10;

    var searchResponse = client.Search<Student>(s => s
        .Aggregations(a => a
            .Terms("student_name", t => t
                .Field(f => f.Name.Suffix("keyword"))
                .Aggregations(aa => aa
                    .TopHits("top_grades", th => th
                        .Sort(so => so
                            .Descending(f => f.Grade)
                        )
                        .Size(topX)
                    )
                )
            )
        )
    );

    var studentNames = searchResponse.Aggregations.Terms("student_name");

    foreach(var bucket in studentNames.Buckets)
    {
        var header = $"Student Name: {bucket.Key}";
        Console.WriteLine(header);
        Console.WriteLine(new string('-', header.Length));
        foreach(var hit in bucket.TopHits("top_grades").Documents<Student>())
        {
            Console.WriteLine($"Id: {hit.Id}, Grade: {hit.Grade}");
        }
        Console.WriteLine();
    }
}

哪个打印出来的

Student Name: Bar
-----------------
Id: 19, Grade: 19
Id: 17, Grade: 17
Id: 15, Grade: 15
Id: 13, Grade: 13
Id: 11, Grade: 11
Id: 9, Grade: 9
Id: 7, Grade: 7
Id: 5, Grade: 5
Id: 3, Grade: 3
Id: 1, Grade: 1

Student Name: Foo
-----------------
Id: 20, Grade: 20
Id: 18, Grade: 18
Id: 16, Grade: 16
Id: 14, Grade: 14
Id: 12, Grade: 12
Id: 10, Grade: 10
Id: 8, Grade: 8
Id: 6, Grade: 6
Id: 4, Grade: 4
Id: 2, Grade: 2

有几个问题

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