octicon-rss(16/)
You've already forked yii2
mirror of
https://github.com/yiisoft/yii2.git
synced 2025-11-10 02:13:17 +08:00
polished elasticsearch AR api, added mget and fixed AR::equals()
This commit is contained in:
octicon-git-branch(16/)
octicon-tag(16/)
octicon-diff(16/tw-mr-1) 6 changed files with 282 additions and 26 deletions
@@ -132,7 +132,7 @@ class ActiveRecord extends Model
|
||||
* - an array of name-value pairs: query by a set of column values and return a single record matching all of them.
|
||||
* - null: return a new [[ActiveQuery]] object for further query purpose.
|
||||
*
|
||||
* @return ActiveQuery|ActiveRecord|null When `$q` is null, a new [[ActiveQuery]] instance
|
||||
* @return ActiveQuery|ActiveQueryInterface|static|null When `$q` is null, a new [[ActiveQuery]] instance
|
||||
* is returned; when `$q` is a scalar or an array, an ActiveRecord object matching it will be
|
||||
* returned (null will be returned if there is no matching).
|
||||
* @throws InvalidConfigException if the AR class does not have a primary key
|
||||
@@ -754,7 +754,7 @@ class ActiveRecord extends Model
|
||||
* [[EVENT_BEFORE_INSERT]], [[EVENT_AFTER_INSERT]] and [[EVENT_AFTER_VALIDATE]]
|
||||
* will be raised by the corresponding methods.
|
||||
*
|
||||
* Only the [[changedAttributes|changed attribute values]] will be inserted into database.
|
||||
* Only the [[dirtyAttributes|changed attribute values]] will be inserted into database.
|
||||
*
|
||||
* If the table's primary key is auto-incremental and is null during insertion,
|
||||
* it will be populated with the actual value after insertion.
|
||||
@@ -1179,11 +1179,15 @@ class ActiveRecord extends Model
|
||||
/**
|
||||
* Returns a value indicating whether the given active record is the same as the current one.
|
||||
* The comparison is made by comparing the table names and the primary key values of the two active records.
|
||||
* If one of the records [[isNewRecord|is new]] they are also considered not equal.
|
||||
* @param ActiveRecord $record record to compare to
|
||||
* @return boolean whether the two active records refer to the same row in the same database table.
|
||||
*/
|
||||
public function equals($record)
|
||||
{
|
||||
if ($this->isNewRecord || $record->isNewRecord) {
|
||||
return false;
|
||||
}
|
||||
return $this->tableName() === $record->tableName() && $this->getPrimaryKey() === $record->getPrimaryKey();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ use yii\helpers\StringHelper;
|
||||
* @author Carsten Brandt <mail@cebe.cc>
|
||||
* @since 2.0
|
||||
*/
|
||||
abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
class ActiveRecord extends \yii\db\ActiveRecord
|
||||
{
|
||||
private $_id;
|
||||
private $_version;
|
||||
@@ -48,7 +48,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
{
|
||||
$query = static::createQuery();
|
||||
if (is_array($q)) {
|
||||
if (count($q) == 1 && isset($q['primaryKey'])) {
|
||||
if (count($q) == 1 && (array_key_exists('primaryKey', $q))) {
|
||||
return static::get($q['primaryKey']);
|
||||
}
|
||||
return $query->where($q)->one();
|
||||
@@ -58,8 +58,23 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a record by its primary key.
|
||||
*
|
||||
* @param mixed $primaryKey the primaryKey value
|
||||
* @param array $options options given in this parameter are passed to elasticsearch
|
||||
* as request URI parameters.
|
||||
*
|
||||
* Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html)
|
||||
* for more details on these options.
|
||||
* @return static|null The record instance or null if it was not found.
|
||||
*/
|
||||
|
||||
public static function get($primaryKey, $options = [])
|
||||
{
|
||||
if ($primaryKey === null) {
|
||||
return null;
|
||||
}
|
||||
$command = static::getDb()->createCommand();
|
||||
$result = $command->get(static::index(), static::type(), $primaryKey, $options);
|
||||
if ($result['exists']) {
|
||||
@@ -68,6 +83,34 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of records by its primary keys.
|
||||
*
|
||||
* @param array $primaryKeys an array of primaryKey values
|
||||
* @param array $options options given in this parameter are passed to elasticsearch
|
||||
* as request URI parameters.
|
||||
*
|
||||
* Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html)
|
||||
* for more details on these options.
|
||||
* @return static|null The record instance or null if it was not found.
|
||||
*/
|
||||
|
||||
public static function mget($primaryKeys, $options = [])
|
||||
{
|
||||
if (empty($primaryKeys)) {
|
||||
return [];
|
||||
}
|
||||
$command = static::getDb()->createCommand();
|
||||
$result = $command->mget(static::index(), static::type(), $primaryKeys, $options);
|
||||
$models = [];
|
||||
foreach($result['docs'] as $doc) {
|
||||
if ($doc['exists']) {
|
||||
$models[] = static::create($doc);
|
||||
}
|
||||
}
|
||||
return $models;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -117,7 +160,12 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
*/
|
||||
public function getOldPrimaryKey($asArray = false)
|
||||
{
|
||||
return $this->getPrimaryKey($asArray);
|
||||
$id = $this->isNewRecord ? null : $this->_id;
|
||||
if ($asArray) {
|
||||
return ['primaryKey' => $id];
|
||||
} else {
|
||||
return $this->_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,12 +190,17 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
throw new InvalidConfigException('The attributes() method of elasticsearch ActiveRecord has to be implemented by child classes.');
|
||||
}
|
||||
|
||||
// TODO index and type definition
|
||||
/**
|
||||
* @return string the name of the index this record is stored in.
|
||||
*/
|
||||
public static function index()
|
||||
{
|
||||
return Inflector::pluralize(Inflector::camel2id(StringHelper::basename(get_called_class()), '-'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the name of the type of this record.
|
||||
*/
|
||||
public static function type()
|
||||
{
|
||||
return Inflector::camel2id(StringHelper::basename(get_called_class()), '-');
|
||||
@@ -168,9 +221,56 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDocs
|
||||
* Inserts a document into the associated index using the attribute values of this record.
|
||||
*
|
||||
* This method performs the following steps in order:
|
||||
*
|
||||
* 1. call [[beforeValidate()]] when `$runValidation` is true. If validation
|
||||
* fails, it will skip the rest of the steps;
|
||||
* 2. call [[afterValidate()]] when `$runValidation` is true.
|
||||
* 3. call [[beforeSave()]]. If the method returns false, it will skip the
|
||||
* rest of the steps;
|
||||
* 4. insert the record into database. If this fails, it will skip the rest of the steps;
|
||||
* 5. call [[afterSave()]];
|
||||
*
|
||||
* In the above step 1, 2, 3 and 5, events [[EVENT_BEFORE_VALIDATE]],
|
||||
* [[EVENT_BEFORE_INSERT]], [[EVENT_AFTER_INSERT]] and [[EVENT_AFTER_VALIDATE]]
|
||||
* will be raised by the corresponding methods.
|
||||
*
|
||||
* Only the [[dirtyAttributes|changed attribute values]] will be inserted into database.
|
||||
*
|
||||
* If the [[primaryKey|primary key]] is not set (null) during insertion,
|
||||
* it will be populated with a
|
||||
* [randomly generated value](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html#_automatic_id_generation)
|
||||
* after insertion.
|
||||
*
|
||||
* For example, to insert a customer record:
|
||||
*
|
||||
* ~~~
|
||||
* $customer = new Customer;
|
||||
* $customer->name = $name;
|
||||
* $customer->email = $email;
|
||||
* $customer->insert();
|
||||
* ~~~
|
||||
*
|
||||
* @param boolean $runValidation whether to perform validation before saving the record.
|
||||
* If the validation fails, the record will not be inserted into the database.
|
||||
* @param array $attributes list of attributes that need to be saved. Defaults to null,
|
||||
* meaning all attributes will be saved.
|
||||
* @param array $options options given in this parameter are passed to elasticsearch
|
||||
* as request URI parameters. These are among others:
|
||||
*
|
||||
* - `routing` define shard placement of this record.
|
||||
* - `parent` by giving the primaryKey of another record this defines a parent-child relation
|
||||
* - `timestamp` specifies the timestamp to store along with the document. Default is indexing time.
|
||||
*
|
||||
* Please refer to the [elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-index_.html)
|
||||
* for more details on these options.
|
||||
*
|
||||
* By default the `op_type` is set to `create`.
|
||||
* @return boolean whether the attributes are valid and the record is inserted successfully.
|
||||
*/
|
||||
public function insert($runValidation = true, $attributes = null)
|
||||
public function insert($runValidation = true, $attributes = null, $options = ['op_type' => 'create'])
|
||||
{
|
||||
if ($runValidation && !$this->validate($attributes)) {
|
||||
return false;
|
||||
@@ -182,7 +282,8 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
static::index(),
|
||||
static::type(),
|
||||
$values,
|
||||
$this->getPrimaryKey()
|
||||
$this->getPrimaryKey(),
|
||||
$options
|
||||
);
|
||||
|
||||
if (!$response['ok']) {
|
||||
@@ -268,7 +369,7 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
}
|
||||
$bulk = '';
|
||||
foreach((array) $condition as $pk) {
|
||||
$bulk = Json::encode([
|
||||
$bulk .= Json::encode([
|
||||
"delete" => [
|
||||
"_id" => $pk,
|
||||
"_type" => static::type(),
|
||||
@@ -283,10 +384,9 @@ abstract class ActiveRecord extends \yii\db\ActiveRecord
|
||||
$body = Json::decode($response->getBody(true));
|
||||
$n=0;
|
||||
foreach($body['items'] as $item) {
|
||||
if ($item['delete']['ok']) {
|
||||
if ($item['delete']['found'] && $item['delete']['ok']) {
|
||||
$n++;
|
||||
}
|
||||
// TODO might want to update the _version in update()
|
||||
}
|
||||
return $n;
|
||||
}
|
||||
|
||||
@@ -115,6 +115,36 @@ class Command extends Component
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets multiple documents from the index
|
||||
*
|
||||
* TODO allow specifying type and index + fields
|
||||
* @param $index
|
||||
* @param $type
|
||||
* @param $id
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
* @see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-get.html
|
||||
*/
|
||||
public function mget($index, $type, $ids, $options = [])
|
||||
{
|
||||
$httpOptions = [
|
||||
'exceptions' => false,
|
||||
];
|
||||
$body = Json::encode(['ids' => array_values($ids)]);
|
||||
$response = $this->db->http()->post( // TODO guzzle does not manage to send get request with content
|
||||
$this->createUrl([$index, $type, '_mget'], $options),
|
||||
null,
|
||||
$body,
|
||||
$httpOptions
|
||||
)->send();
|
||||
if ($response->getStatusCode() == 200) {
|
||||
return Json::decode($response->getBody(true));
|
||||
} else {
|
||||
throw new Exception('Elasticsearch request failed.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gets a documents _source from the index (>=v0.90.1)
|
||||
* @param $index
|
||||
|
||||
Reference in New Issue
Block a user