2016-08-18 17 views
5

Tôi đã tạo ra một chỉ số trong đàn hồi bằng cách sử dụng truy vấn sau đây:ElasticSearch Nest Insert/Update

PUT public_site 
{ 
    "mappings": { 
    "page": { 
     "properties": { 
     "url": { 
      "type": "string" 
     }, 
     "title":{ 
      "type": "string" 
     }, 
     "body":{ 
      "type": "string" 
     }, 
     "meta_description":{ 
      "type": "string" 
     }, 
     "keywords":{ 
      "type": "string" 
     }, 
     "category":{ 
      "type": "string" 
     }, 
     "last_updated_date":{ 
      "type": "date" 
     }, 
     "source_id":{ 
     "type":"string" 
     } 
     } 
    } 
    } 
} 

Tôi muốn chèn một tài liệu vào chỉ tiêu này bằng cách sử dụng thư viện .net NEST. Vấn đề của tôi là chữ ký của phương thức cập nhật .net không có ý nghĩa gì đối với tôi.

client.Update<TDocument>(IUpdateRequest<TDocument,TPartialDocument>) 

Thư viện Java làm nhiều hơn nữa ý nghĩa với tôi:

UpdateRequest updateRequest = new UpdateRequest(); 
updateRequest.index("index"); 
updateRequest.type("type"); 
updateRequest.id("1"); 
updateRequest.doc(jsonBuilder() 
     .startObject() 
      .field("gender", "male") 
     .endObject()); 
client.update(updateRequest).get(); 

Trong NEST nơi nào các TDocument và TPartialDocument lớp đến từ đâu? Các lớp C# này tôi có thể đại diện cho chỉ mục của mình không?

Trả lời

13

TDocumentTPartialDocument là các thông số chung chung kiểu cho loại POCO rằng

  • đại diện cho một tài liệu Elasticsearch (TDocument) và
  • một đại diện của một phần của các tài liệu Elasticsearch (TPartialDocument), khi thực hiện cập nhật một phần.

Trong trường hợp cập nhật đầy đủ, TDocumentTPartialDocument có thể tham chiếu cùng loại POCO cụ thể. Chúng ta hãy xem xét một số ví dụ để chứng minh.

Hãy tạo chỉ mục với ánh xạ mà bạn đã xác định ở trên. Thứ nhất, chúng ta có thể đại diện cho một tài liệu sử dụng một loại POCO

public class Page 
{ 
    public string Url { get; set; } 

    public string Title { get; set; } 

    public string Body { get; set; } 

    [String(Name="meta_description")] 
    public string MetaDescription { get; set; } 

    public IList<string> Keywords { get; set; } 

    public string Category { get; set; } 

    [Date(Name="last_updated_date")] 
    public DateTimeOffset LastUpdatedDate { get; set; } 

    [String(Name="source_id")] 
    public string SourceId { get; set; } 
} 

Theo mặc định, khi tổ chức NEST serializes tính POCO nó sử dụng quy ước đặt tên con lạc đà vỏ. Bởi vì chỉ mục của bạn có vỏ rắn cho một số thuộc tính, ví dụ: "last_updated_date", chúng ta có thể ghi đè tên mà NEST tuần tự hóa chúng để sử dụng các thuộc tính.

Tiếp theo, hãy tạo cho khách hàng để làm việc với các thiết lập

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); 
var pagesIndex = "pages"; 
var connectionSettings = new ConnectionSettings(pool) 
     .DefaultIndex(pagesIndex) 
     .PrettyJson() 
     .DisableDirectStreaming() 
     .OnRequestCompleted(response => 
      { 
       // log out the request 
       if (response.RequestBodyInBytes != null) 
       { 
        Console.WriteLine(
         $"{response.HttpMethod} {response.Uri} \n" + 
         $"{Encoding.UTF8.GetString(response.RequestBodyInBytes)}"); 
       } 
       else 
       { 
        Console.WriteLine($"{response.HttpMethod} {response.Uri}"); 
       } 

       Console.WriteLine(); 

       // log out the response 
       if (response.ResponseBodyInBytes != null) 
       { 
        Console.WriteLine($"Status: {response.HttpStatusCode}\n" + 
          $"{Encoding.UTF8.GetString(response.ResponseBodyInBytes)}\n" + 
          $"{new string('-', 30)}\n"); 
       } 
       else 
       { 
        Console.WriteLine($"Status: {response.HttpStatusCode}\n" + 
          $"{new string('-', 30)}\n"); 
       } 
      }); 

var client = new ElasticClient(connectionSettings); 

kết nối đã được cấu hình theo cách đó là hữu ích trong khi đang phát triển;

  1. DefaultIndex() - Chỉ mục mặc định đã được định cấu hình là "pages". Nếu không có tên chỉ mục rõ ràng nào được chuyển vào một yêu cầu và không có tên chỉ mục nào có thể được suy ra cho một POCO, thì chỉ mục mặc định sẽ được sử dụng.
  2. PrettyJson() - Làm mới yêu cầu và câu trả lời của json (thụt lề). Điều này sẽ hữu ích để xem những gì đang được gửi đến và nhận được từ Elasticsearch.
  3. DisableDirectStreaming() - NEST theo mặc định sẽ tuần tự hóa POCO thành luồng yêu cầu và deserializes các loại phản hồi từ luồng phản hồi. Vô hiệu hóa luồng trực tiếp này sẽ đệm yêu cầu và byte phản hồi trong luồng bộ nhớ, cho phép chúng tôi ghi lại chúng trong OnRequestCompleted()
  4. OnRequestCompleted() - Được gọi sau khi nhận được phản hồi. Điều này cho phép chúng tôi đăng xuất các yêu cầu và phản hồi trong khi chúng tôi đang phát triển.

2, 3 và 4 rất hữu ích trong quá trình phát triển nhưng sẽ đi kèm với một số chi phí hoạt động để bạn có thể quyết định không sử dụng chúng trong sản xuất.

Bây giờ, chúng ta hãy tạo ra các chỉ mục với trang ánh xạ

// delete the index if it exists. Useful for demo purposes so that 
// we can re-run this example. 
if (client.IndexExists(pagesIndex).Exists) 
    client.DeleteIndex(pagesIndex); 

// create the index, adding the mapping for the Page type to the index 
// at the same time. Automap() will infer the mapping from the POCO 
var createIndexResponse = client.CreateIndex(pagesIndex, c => c 
    .Mappings(m => m 
     .Map<Page>(p => p 
      .AutoMap() 
     ) 
    ) 
); 

Take a look at the automapping documentation for more details around how you can control mapping for POCO types

lập chỉ mục trang kiểu mới được đơn giản như

// create a sample Page 
var page = new Page 
{ 
    Title = "Sample Page", 
    Body = "Sample Body", 
    Category = "sample", 
    Keywords = new List<string> 
    { 
     "sample", 
     "example", 
     "demo" 
    }, 
    LastUpdatedDate = DateTime.UtcNow, 
    MetaDescription = "Sample meta description", 
    SourceId = "1", 
    Url = "/pages/sample-page" 
}; 

// index the sample Page into Elasticsearch. 
// NEST will infer the document type (_type) from the POCO type, 
// by default it will camel case the POCO type name 
var indexResponse = client.Index(page); 

chỉ mục tài liệu sẽ tạo ra các tài liệu nếu nó không tồn tại hoặc ghi đè lên một tài liệu hiện có nếu nó tồn tại. Elasticsearch has optimistic concurrency control có thể được sử dụng để kiểm soát cách hoạt động này trong các điều kiện khác nhau.

Chúng tôi có thể cập nhật tài liệu bằng cách sử dụng các phương pháp Update, nhưng trước tiên là một nền tảng nhỏ.

Chúng tôi có thể lấy tài liệu từ Elasticsearch bằng cách chỉ định chỉ mục, loại và id. NEST làm cho điều này dễ dàng hơn một chút bởi vì chúng ta có thể phỏng đoán tất cả những điều này từ POCO. Khi chúng tôi tạo bản đồ của mình, chúng tôi đã không chỉ định thuộc tính Id trên POCO; nếu NEST thấy thuộc tính được gọi là Id, nó sử dụng tên này làm id cho tài liệu nhưng vì chúng tôi không có tài khoản, đó không phải là vấn đề vì Elasticsearch sẽ tạo id cho tài liệu và đặt nó trong siêu dữ liệu tài liệu. Tuy nhiên, vì siêu dữ liệu tài liệu tách biệt với tài liệu nguồn, điều này có thể làm cho các tài liệu mô hình hóa như các loại POCO phức tạp hơn một chút (nhưng không phải là không thể); đối với một câu trả lời cụ thể, chúng tôi sẽ có quyền truy cập vào id của tài liệu thông qua siêu dữ liệu và truy cập vào nguồn thông qua trường _source. Chúng ta có thể kết hợp id với nguồn của chúng ta trong ứng dụng.

Một cách dễ dàng hơn để giải quyết vấn đề này là có id trên POCO. Chúng tôi có thể chỉ định một thuộc tính Id trên POCO và điều này sẽ được sử dụng làm id của tài liệu, nhưng chúng tôi không phải gọi cho bất động sản Id nếu chúng tôi không muốn và nếu không, chúng tôi cần nói NEST thuộc tính nào đại diện cho id. Điều này có thể được thực hiện với một thuộc tính. Giả sử rằng SourceId là một id duy nhất cho một cá thể Page, hãy sử dụng thuộc tính ElasticsearchTypeAttributeIdProperty để chỉ định điều này. Có lẽ chúng ta không nên cũng phân tích chuỗi này nhưng chỉ số nó đúng nguyên văn, chúng ta có thể cũng kiểm soát này thông qua Index tài sản của thuộc tính trên tài sản

[ElasticsearchType(IdProperty = nameof(SourceId))] 
public class Page 
{ 
    public string Url { get; set; } 

    public string Title { get; set; } 

    public string Body { get; set; } 

    [String(Name="meta_description")] 
    public string MetaDescription { get; set; } 

    public IList<string> Keywords { get; set; } 

    public string Category { get; set; } 

    [Date(Name="last_updated_date")] 
    public DateTimeOffset LastUpdatedDate { get; set; } 

    [String(Name="source_id", Index=FieldIndexOption.NotAnalyzed)] 
    public string SourceId { get; set; } 
} 

Với những tại chỗ, chúng tôi sẽ cần phải tái lập chỉ mục như trước để những thay đổi này được phản ánh trong ánh xạ và NEST có thể sử dụng cấu hình này khi lập chỉ mục một cá thể Page.

Bây giờ, trở lại cập nhật :) Chúng tôi có thể nhận được một tài liệu từ Elasticsearch, cập nhật nó trong ứng dụng và sau đó tái-index nó

var getResponse = client.Get<Page>("1"); 

var page = getResponse.Source; 

// update the last updated date 
page.LastUpdatedDate = DateTime.UtcNow; 

var updateResponse = client.Update<Page>(page, u => u.Doc(page)); 

Đối số đầu tiên là id cho các tài liệu chúng tôi muốn nhận được có thể được suy ra bởi NEST từ cá thể Page.Kể từ khi chúng tôi đang đi qua các tài liệu toàn bộ trở lại đây, chúng ta có thể vừa sử dụng .Index() thay vì Update(), vì chúng ta đang cập nhật tất cả các lĩnh vực

var indexResponse = client.Index(page); 

Tuy nhiên, vì chúng tôi chỉ muốn cập nhật LastUpdatedDate, phải lấy tài liệu từ Elasticsearch, cập nhật nó trong ứng dụng, sau đó gửi tài liệu trở lại Elasticsearch là rất nhiều công việc. Chúng tôi chỉ có thể gửi cập nhật LastUpdatedDate tới Elasticsearch thay vì sử dụng tài liệu một phần. C# loại vô danh là thực sự hữu ích ở đây

// model our partial document with an anonymous type. 
// Note that we need to use the snake casing name 
// (NEST will still camel case the property names but this 
// doesn't help us here) 
var lastUpdatedDate = new 
{ 
    last_updated_date = DateTime.UtcNow 
}; 

// do the partial update. 
// Page is TDocument, object is TPartialDocument 
var partialUpdateResponse = client.Update<Page, object>("1", u => u 
    .Doc(lastUpdatedDate) 
); 

Chúng ta có thể sử dụng kiểm soát đồng thời lạc quan ở đây nếu chúng ta cần phải sử dụng RetryOnConflict(int)

var partialUpdateResponse = client.Update<Page, object>("1", u => u 
    .Doc(lastUpdatedDate) 
    .RetryOnConflict(1) 
); 

Với một bản cập nhật phần, Elasticsearch sẽ nhận được tài liệu, áp dụng bản cập nhật phần và sau đó chỉ mục tài liệu được cập nhật; nếu tài liệu thay đổi giữa nhận và cập nhật, Elasticsearch sẽ thử lại lần nữa dựa trên RetryOnConflict(1).

Hy vọng rằng sẽ giúp :)

+1

câu trả lời tuyệt vời và giải thích rõ ràng cho tôi. – Chan

Các vấn đề liên quan