tiết kiệm nhanh giá trị trường đơn


19

Tôi đã có khoảng 70k nút loại được chỉ định trên trang web của mình. Tôi cần chạy một bản cập nhật về chúng. Một số thao tác và đặt một trường thành giá trị mong muốn. node_savelà rất chậm và nó gây ra sự cố (quá lâu callstack mayby). Có cách nào nhanh hơn để viết thông tin về một lĩnh vực cụ thể này không?

Đã được field_attach_updateđề cập trong một bài viết, nhưng nó không nhanh hơn nhiều.

EDIT: Có chế độ xem khá phức tạp được xây dựng trên loại nút này, nhưng không hoạt động trên trường này mà tôi muốn cập nhật.

Câu trả lời:


30

Tôi chắc chắn sẽ đi cho field_attach_update.

Ý tưởng rất đơn giản. Chỉ cần tải nút và lưu nó bằng cách sử dụng field_attach_update.

Vd

$node = node_load($nid);
$node->field_name[LANGUAGE_NONE][0]['value'] = 'New value';
field_attach_presave('node', $node);
field_attach_update('node', $node);
  // Clear the static loading cache.
entity_get_controller('node')->resetCache(array($node->nid));

Điều này sẽ không thay đổi bất kỳ dấu thời gian hoặc bất kỳ hook nào khác mà node_save thường gọi. Tải nút cũng sẽ gọi một số hook nên có thể nó không hiệu quả.

Nếu bạn có nid và nếu cấu trúc nút bị chết đơn giản, bạn cũng có thể làm điều đó như thế này:

 $node = new stdClass();
 $node->nid = $nid; // Enter the nid taken. Make sure it exists. 
 $node->type = 'article';
 $node->field_name[LANGUAGE_NONE][0]['value'] = 'New value';
 field_attach_presave('node', $node);
 field_attach_update('node', $node);
  // Clear the static loading cache.
 entity_get_controller('node')->resetCache(array($node->nid));

Dù sao, nếu bạn đang cố gắng cập nhật bất cứ điều gì ngoài các trường, điều này sẽ không hoạt động (trạng thái bình luận, trạng thái được xuất bản, v.v.). Ngoài ra Nếu bạn đang sử dụng node_save, bộ đệm cho nút cụ thể sẽ tự động bị xóa đối với các phương thức khác nhau, chúng tôi cần xóa nó bằng 'entity_get_controll'.

Cập nhật: Dường như bạn cũng nên gọi field_attach_presave()để cho các mô-đun khác xử lý trường nhập đúng cách. Ví dụ, mô-đun tệp sử dụng nó để đặt trạng thái tệp thành vĩnh viễn bằng cách sử dụng móc này. Tôi đã cập nhật 2 ví dụ của tôi ở trên.


Tôi có nid nhưng cấu trúc không đơn giản cho nút, nhưng trường tôi muốn cập nhật thì đơn giản. Những gì tôi có thể mong đợi từ chỉ thiết lập một trường cho nút hiện tại (được xác định bởi nid nhưng không được tải) và sau đó gọi field_attach_update?
Eloar

4
Khi nó sử dụng truy vấn thực thể đã làm mọi thứ chậm lại. Vì vậy, chuyển đổi từ node_saveđến field_attach_updatevà từ EntityFieldQueryđến db_query_rangelà khá bổ ích. Từ 3h cập nhật lên 40 phút.
Eloar

2

Nếu bạn không muốn lưu dữ liệu trường mà không khiến các sự kiện và hành động tiêu chuẩn xảy ra thì bạn có thể sử dụng drupal_write_record .

Dưới đây là một ví dụ để chèn Hello World vào trường cơ thể cho một nút loại bài viết có id là 1.

$values = array(
  'entity_type' => 'node',
  'bundle' => 'article',
  'entity_id' => 1,
  'revision_id' => 1,
  'language' => 'und',
  'delta' => 0,
  'body_value' => 'HELLO WORLD',
  'body_summary' => '',
  'body_format' => 'filtered_html',
);
drupal_write_record('field_data_body', $values);
drupal_write_record('field_revision_body', $values);

Nếu trang web của bạn là đa ngôn ngữ thì bạn sẽ muốn sử dụng 'en' hoặc ngôn ngữ của nội dung của bạn thay vì 'und'.

Nếu bạn đang thực hiện sửa đổi, bạn sẽ phải cẩn thận để chèn id sửa đổi đúng, nếu không, bạn có thể chỉ cần chèn cùng một giá trị như entity_id.

Lưu ý cách dữ liệu này được chèn vào hai bảng field_data_ * và field_Vvision_ *. Bạn nên chèn vào cả hai để đảm bảo trang web hoạt động như mong muốn.

Sau khi chạy, bạn sẽ cần xóa bộ nhớ cache để các trường hiển thị tùy thuộc vào cách thiết lập bộ đệm của bạn.


2

Đối với một bản cập nhật đơn giản như thế này, nơi rất nhiều nút cần được cập nhật, tôi luôn sử dụng câu lệnh cập nhật MySQL. Có, bộ nhớ đệm cần được xem xét nhưng bạn chỉ có thể xóa bộ đệm sau khi bạn hoàn thành và tất cả đều tốt. Tất nhiên, bạn cần phải làm quen với cấu trúc dữ liệu nhưng nó tương đối đơn giản trong Drupal 6. (mặc dù khủng khiếp trong Drupal 7)


Project được tạo cho Drupal 7. Sau khi tất cả các phần trong mô-đun của tôi được tạo ra để thao tác trực tiếp trên cấu trúc Drupal DB để đọc các giá trị và tìm kiếm vì các truy vấn sql nhanh hơn nhiều so với EntityFieldQueries.
Eloar

2

Tôi cũng đề xuất field_attach_updatevà không phải là truy vấn SQL trực tiếp, vì sql không cập nhật đối tượng bộ đệm nút và trong lần tiếp theo node_loadbạn sẽ không tải giá trị trường được cập nhật, bạn sẽ tải giá trị cũ

field_attach_update tốt hơn nhiều so với truy vấn SQL trực tiếp.


Ayesh K đề nghị tạo nút làm stdClassđối tượng mà không tải. Bạn có biết điều gì có thể xảy ra nếu tôi cố cập nhật nút theo cách này mà không đặt tất cả các trường không? Những người sẽ được ghi đè bằng null hoặc mặc định? Mayby những người sẽ được bỏ qua bởi quá trình cập nhật?
Eloar

1
Bạn có thể lưu nút trực tiếp bằng phương pháp Ayeshs (stdClass mới, v.v.) chỉ UI mới xác thực trên các trường bắt buộc
pico34 11/03/13

Tôi sẽ cố gắng cập nhật nút bằng phương pháp này mà không đặt tất cả các trường và kiểm tra xem điều gì sẽ xảy ra. Nó có thể là phương pháp nhanh nhất để cập nhật các nút trong quy trình cập nhật mô-đun (lô).
Eloar

2

Đã thử tất cả các cách tiếp cận được đề cập trong các câu trả lời khác, tôi nhận được thời gian cập nhật rất chậm (khoảng 7 ngày đối với 700.000 nút của loại nút có hơn 20 trường) cho đến khi tôi tìm thấy bài viết này: http://www.drupalonwindows.com/en/ blog / only-update-change-Field-or-property-entity-drupal .

Sau khi thực hiện một cái gì đó giống như đoạn mã dưới đây trong hook_update, tôi đã giảm thời gian cập nhật xuống còn 2 giờ, mà tôi nghĩ là có thể quản lý được.

if (!isset($sandbox['storage']['nids'])) {
    $sandbox['storage']['nids'] = [];
    $query = 'SELECT {nid} FROM node WHERE type = \'article\';';
    $result = db_query($query)->fetchCol();
    if ($result) {
      $sandbox['storage']['nids'] = $result;
      $sandbox['storage']['total'] = count($sandbox['storage']['nids']);
      $sandbox['storage']['last_run_time'] = time();
      $sandbox['progress'] = 0;
    }
  }

  $amount = 300;
  $nids = array_slice($sandbox['storage']['nids'], 0, $amount);

  if (!empty($nids)) {
    $nodes = node_load_multiple($nids, [], TRUE);
    foreach ($nodes as $node) {
      // Lets manipualte the entity.
      $article_wrapper = UtilsEntity::entity_metadata_wrapper('node', $node);
      // Eventual logic here.

        // Field to update
        $article_wrapper->my_field = 'my_value';
        $article_wrapper->save();

    $sandbox['progress']++;
    }
    $sandbox['message'] = 'Runs left: ' . (($sandbox['storage']['total'] - $sandbox['progress'])/$amount) . ' Progress: ' . (($sandbox['progress'] * $amount)/$sandbox['storage']['total']) . '%';
    $sandbox['storage']['last_run_time'] = time();
    unset($nids);
  }
  $sandbox['storage']['nids'] = array_slice($sandbox['storage']['nids'], 100, count($sandbox['storage']['nids']));
  if (!empty($sandbox['storage']['total'])) {
    $sandbox['#finished'] = ($sandbox['storage']['total'] - count($sandbox['storage']['nids'])) / $sandbox['storage']['total'];
  }
  return $sandbox['message'];

1

Tôi thậm chí có cùng yêu cầu cập nhật một trường cho tất cả các nút của một loại nội dung cụ thể. Tôi đã sử dụng node_load_mult Mônfield_attach_update .

$nodes = node_load_multiple(array(), array('type' => 'content_type_name'));
foreach ($nodes as $node) {
  $node->field_name['und'][0]['value'] = 'field value';
  field_attach_update('node', $node);
}

Tôi chạy nó qua drush và nó khá nhanh.


0

Bạn đã xem xét thực hiện các cập nhật này trực tiếp vào cơ sở dữ liệu bằng cách sử dụng myQuery chưa? Đây có lẽ là cách đơn giản nhất và nhanh nhất để đạt được những gì bạn muốn.

Đây là một ví dụ đơn giản. Bạn có thể thực thi một lệnh như vậy từ tab 'SQL' trong phpMyAdmin. Hãy tưởng tượng bạn có một loại nội dung được gọi là Hồ sơ thành viên. Trong đó, bạn có một trường có tên 'Loại thành viên' (ví dụ: công ty, cá nhân, tổ chức). Giả sử bạn muốn cập nhật tất cả các lần xuất hiện cho 'CÔNG TY' thành 'công ty'. Lệnh sau sẽ làm điều đó.

CẬP NHẬT nội dung_type_member_profile SET field_type_of_member_value= 'công ty' WHERE field_type_of_member_value= 'CÔNG TY';

Ngoài ra, hãy kiểm tra Bắt đầu với MySQL


Đây là một trong những lựa chọn. Tôi để nó như là cuối cùng để kiểm tra và thực hiện. Tôi không muốn làm hỏng cấu trúc drupal và sai sót nhiều. Vì vậy, trước tiên tôi tìm kiếm bất kỳ giải pháp nào trực tiếp thông qua API Drupal. Nếu bạn có thể cung cấp một số ví dụ, nó sẽ được đánh giá cao.
Eloar

Điểm Goog. Tôi đã thêm một ví dụ đơn giản vào câu trả lời ban đầu của tôi.
Bisonbleu

eh, tôi biết SQL đủ tốt để cập nhật bất kỳ bản ghi nào trong bất kỳ bảng nào. Nó không phải là vấn đề. Vấn đề là, tôi không đủ quen thuộc với cách lưu trữ dữ liệu của drupal (đặc biệt là siêu dữ liệu). Luôn có rất nhiều bộ nhớ đệm, bảo quản và như vậy trong các hệ thống như vậy, vì vậy việc cập nhật nó ở mức thấp nhất có thể (không phải luôn luôn) làm rối tung một số sai sót. Vì vậy, nếu nói đến điều này, tôi sẽ cố gắng thực hiện nó ở mức thấp nhất, và tôi sẽ sẵn sàng cho một số mớ hỗn độn thực sự.
Eloar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.