/** * Listen to the minute cron in order to sync data to ElasticSearch * * @param string $hook the name of the hook * @param string $type the type of the hook * @param string $returnvalue current return value * @param array $params supplied params * * @return void */ public static function minuteSync($hook, $type, $returnvalue, $params) { $setting = elasticsearch_get_setting('sync'); if ($setting !== 'yes') { // sync not enabled return; } $client = elasticsearch_get_client(); if (empty($client)) { return; } $starttime = (int) elgg_extract('time', $params, time()); // delete first $client->bulkDeleteDocuments(); $update_actions = array('no_index_ts', 'update', 'reindex'); foreach ($update_actions as $action) { $options = elasticsearch_get_bulk_options($action); if (empty($options)) { continue; } $getter = ''; if ($action === 'no_index_ts') { $getter = 'elgg_get_entities'; } $time_left = self::batchSync($options, $starttime, $getter); if ($time_left === false) { return; } } }
public function __construct($params) { $this->default_index = elasticsearch_get_setting('index'); $this->search_alias = elasticsearch_get_setting('search_alias'); $this->search_params = new SearchParams(['client' => $this]); parent::__construct($params); }
/** * Hook to transform a search result to an Elgg Entity * * @param string $hook the name of the hook * @param string $type the type of the hook * @param Client $returnvalue current return value * @param array $params supplied params * * @return void|Client */ public static function sourceToEntity($hook, $type, $returnvalue, $params) { $hit = elgg_extract('hit', $params); $index = elgg_extract('_index', $hit); $elgg_index = elasticsearch_get_setting('index'); if ($index !== $elgg_index) { return; } $source = elgg_extract('_source', $hit); $row = new \stdClass(); foreach ($source as $key => $value) { switch ($key) { case 'subtype': // elastic stores the textual version of the subtype, entity_row_to_elggstar needs the int $row->{$key} = get_subtype_id($source['type'], $value); break; case 'last_action': case 'time_created': case 'time_updated': // convert the timestamps to unix timestamps $value = strtotime($value); default: $row->{$key} = $value; break; } } // enabled attribute is not stored in elasticsearch by default $row->enabled = 'yes'; // specials types if ($row->type == 'user') { // makes sure all attributes are loaded to prevent a db call $external_attributes = \ElggUser::getExternalAttributes(); foreach ($external_attributes as $key => $value) { if (isset($row->{$key})) { continue; } $row->{$key} = $value; } } try { $result = entity_row_to_elggstar($row); } catch (\Exception $e) { elgg_log($e->getMessage(), 'NOTICE'); return; } return $result; }
/** * Get the $options for elgg_get_entities* in order to update the ElasticSearch index * * @param string $type which options to get * * @return false|array */ function elasticsearch_get_bulk_options($type = 'no_index_ts') { $type_subtypes = elasticsearch_get_registered_entity_types(); if (empty($type_subtypes)) { return false; } $dbprefix = elgg_get_config('dbprefix'); switch ($type) { case 'no_index_ts': // new or updated entities return array('type_subtype_pairs' => $type_subtypes, 'limit' => false, 'wheres' => array("NOT EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM {$dbprefix}private_settings ps\n\t\t\t\t\t\tWHERE ps.entity_guid = e.guid\n\t\t\t\t\t\tAND ps.name = '" . ELASTICSEARCH_INDEXED_NAME . "'\n\t\t\t\t\t)", "NOT EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM {$dbprefix}users_entity ue\n\t\t\t\t\t\tWHERE ue.guid = e.guid\n\t\t\t\t\t\tAND ue.banned = 'yes'\n\t\t\t\t\t)")); break; case 'reindex': // a reindex has been initiated, so update all out of date entities $setting = (int) elasticsearch_get_setting('reindex_ts'); if (empty($setting)) { return false; } return array('type_subtype_pairs' => $type_subtypes, 'limit' => false, 'private_setting_name_value_pairs' => array(array('name' => ELASTICSEARCH_INDEXED_NAME, 'value' => $setting, 'operand' => '<'), array('name' => ELASTICSEARCH_INDEXED_NAME, 'value' => 0, 'operand' => '>'))); break; case 'update': // content that was updated in Elgg and needs to be reindexed return array('type_subtype_pairs' => $type_subtypes, 'limit' => false, 'private_setting_name_value_pairs' => array(array('name' => ELASTICSEARCH_INDEXED_NAME, 'value' => 0))); break; case 'count': // content that needs to be indexed return array('type_subtype_pairs' => $type_subtypes, 'count' => true); break; } return false; }
break; } try { $client->indices()->putAlias(array('index' => $index, 'name' => $alias)); } catch (Exception $e) { register_error(elgg_echo('elasticsearch:action:admin:index_management:error:add_alias', array($alias, $index))); break; } system_message(elgg_echo('elasticsearch:action:admin:index_management:add_alias', array($alias, $index))); break; case 'delete_alias': if (!$exists) { register_error(elgg_echo('elasticsearch:error:index_not_exists', array($index))); break; } $alias = elasticsearch_get_setting('search_alias'); if (empty($alias)) { register_error(elgg_echo('elasticsearch:error:alias_not_configured')); break; } $alias_exists = $client->indices()->existsAlias(array('name' => $alias, 'index' => $index)); if (!$alias_exists) { register_error(elgg_echo('elasticsearch:action:admin:index_management:error:delete_alias:exists', array($alias, $index))); break; } try { $client->indices()->deleteAlias(array('index' => $index, 'name' => $alias)); } catch (Exception $e) { register_error(elgg_echo('elasticsearch:action:admin:index_management:error:delete_alias', array($alias, $index))); break; }
$options['count'] = true; $count = elgg_get_entities_from_private_settings($options); $content .= '<tr>'; $content .= '<td>' . elgg_echo('elasticsearch:stats:elgg:update') . '</td>'; $content .= "<td>{$count}</td>"; $content .= '</tr>'; // content to reindex $options = elasticsearch_get_bulk_options('reindex'); $count = 0; if (!empty($options)) { $options['count'] = true; $count = elgg_get_entities_from_private_settings($options); } $content .= '<tr>'; $content .= '<td>' . elgg_echo('elasticsearch:stats:elgg:reindex'); $reindex_title = elgg_echo('elasticsearch:stats:elgg:reindex:action'); $last_ts = (int) elasticsearch_get_setting('reindex_ts'); if (!empty($last_ts)) { $reindex_title .= ' ' . elgg_echo('elasticsearch:stats:elgg:reindex:last_ts', [date('c', $last_ts)]); } $content .= elgg_view('output/url', ['confirm' => true, 'href' => 'action/elasticsearch/admin/reindex', 'text' => elgg_view_icon('refresh'), 'title' => $reindex_title, 'class' => 'mlm']); $content .= '</td>'; $content .= "<td>{$count}</td>"; $content .= '</tr>'; $count = count(elasticsearch_get_documents_for_deletion()); $content .= '<tr>'; $content .= '<td>' . elgg_echo('elasticsearch:stats:elgg:delete') . '</td>'; $content .= "<td>{$count}</td>"; $content .= '</tr>'; $content .= '</table>'; echo elgg_view_module('inline', elgg_echo('elasticsearch:stats:elgg'), $content);