eZFind how to force update of object relationslist

Author Message

Lars Eirik R

Wednesday 10 November 2010 5:56:36 am

My article has a related content which has changed its name. This name needs to be reflected in the lucene index as well. Is there an easy way to do this?

It seems to not help just to republish the article..

Patrick Kaiser

Wednesday 10 November 2010 8:39:26 am

I wrote a simple script to do that. There may be smarter ways to archive this, but the script works fine for me. Just adjust the settings under configuration..

<?php
/**
 * Script to update Objects to respect changes in related Objects
 * 
 * Drop this file in your ez doc-root and adjust the settings
 * then run: ezdocroot # php update_related_object_attributes.php
 * 
 * @author Patrick Kaiser <pk@okapi.de>
 * @version 1.0
 */


// Configuration

// Parent node_id where to fetch the objects from
$fetch_parent_node = 80;

// how many objects should be fetched, use offset?
$fetch_limit = 1000;
$fetch_offset = 0;

// define the content_classes to fetch
$fetch_include_content_classes = array( 
    'program' 
);

// set this to the user_id you want (must have permissions to read and edit the objects
$modify_user_id = 14;

// define the attribute_identifiers which hold object relations you want to update
$related_attributes = array( 
    'related_languages', 'related_regions_countries', 'related_program_lenght', 'related_pre_experience' 
);

// END Configuration



// ez bootstrap
require_once 'autoload.php';

// ez script init
$script_params = array( 
    'description' => "Script to update Objects to respect changes in related Objects", 'use-session' => false, 
    'use-modules' => true, 'use-extensions' => true, 'user' => true 
);
$script = eZScript::instance( $script_params );
$script->startup();
$script->initialize();

// init cli instance
$cli = eZCLI::instance();
$cli->setUseStyles( true );
$cli->output( $cli->stylize( 'cyan', "Starting to update object relations \n\n" ), false );

// set ez user
$user = eZUser::fetch( $modify_user_id );
eZUser::setCurrentlyLoggedInUser( $user, $modify_user_id );

// fetch params
$fetch_params = array( 
    'Limit' => $fetch_limit, 'ClassFilterType' => 'include', 'ClassFilterArray' => $fetch_include_content_classes, 
    'Offset' => $fetch_offset 
);
$objects_to_update = eZContentObjectTreeNode::subTreeByNodeID( $fetch_params, $fetch_parent_node );


$search_engine = new eZSolr();
$update_count = count( $objects_to_update );
foreach( $objects_to_update as $index => $object_to_update )
{
    $cli->output( $cli->stylize( 'red', "Updating Object {$index} of {$update_count}\n" ), false );
    
    // get the actual object
    $object = $object_to_update->attribute( 'object' );
    
    // print debug information
    $debug = "-- ID: {$object->ID}\n";
    $debug .= "-- Name: {$object->Name}\n";
    $cli->output( $debug, false );
    
    // get the data_map
    $data_map = $object_to_update->attribute( 'data_map' );
    
    // loop through the related_objects attributes
    foreach( $related_attributes as $rel_attr_id )
    {
        if( !isset( $data_map[ $rel_attr_id ] ))
            continue;
            
        $cli->output( $cli->stylize( 'cyan', "Updating relations for attribute {$rel_attr_id}\n" ), false );
        
        // get the attribute
        $rel_attr = $data_map[ $rel_attr_id ];
        $rel_attr_content = $rel_attr->Content();
        
        // store the object ids
        $rel_attr_obj_ids = array();
        foreach( $rel_attr_content[ 'relation_list' ] as $relObject )
        {
            $rel_attr_obj_ids[] = $relObject[ 'contentobject_id' ];
        }
        
        $debug = "-- FOUND " . count( $rel_attr_obj_ids ) . " Relations to update...\n";
        $cli->output( $debug, false );
        
        // init new objectrelation attribute
        $newRelationList = new eZObjectRelationListType();
        
        // prepare the value to use with toString ("123-34657-58756")
        $newRelationListString = implode( "-", $rel_attr_obj_ids );
        
        $debug = "-- newRelationListString: {$newRelationListString}\n";
        $cli->output( $debug, false );
        
        // use toString method to set the value and store the attribute
        $newRelationList->fromString( $rel_attr, $newRelationListString );
        $rel_attr->store();
    }
    
    // save the object
    $object->store();
    
    $debug = "-- New relations stored, updating Solr...\n";
    $cli->output( $debug, false );
    
    // trigger reindexing the document with solr
    $search_engine->addObject( $object, true );
    
    $debug = "-- Done ...\n\n";
    $cli->output( $debug, false );
}


$cli->output( "\n", false );
$script->shutdown();
?>


Best regards,

Patrick

Lars Eirik R

Thursday 11 November 2010 5:04:20 am

Thanks for the code:)

I have tried to run it and the script executes nicely, however the object relations do not update to reflect the name of the recently changed object.

I am not sure how to solve that.

i have an object with the name "People". All articles which are associated with "Peopl" now needs to be changed with the tag "People and places". Stored in the lucene document originally is "People", so when i do a search all articles initially will match and present themselfes as i want to.

However if People and Places is the new name, then this has to be reflected in the lucene document as well. I was hoping that $search_enging->addObject() would do this, but i am not able to get it to work:(

Thanks for helping and feel free to update with your ideas:)

Patrick Kaiser

Thursday 11 November 2010 6:58:36 am

Hm, strange. Which types of relations do you use?

My script only works for the object_relations datatype.

The "problem" with this datatype is, that it not only stores the object_ids of the related objects, but also their versions. The script actually does nothing else then to re-relate the existing related_objects to the newest version.

And you are right, reindexing to solr actually happens here:

$search_engine->addObject($object,true);

Mayby you could try to run updatesearchindexsolr, just to make sure you have a fresh and clean index.

php extension/ezfind/bin/php/updatesearchindexsolr.php -s YOUR_SITEACCESS -d all -v --php-exec=php --clean-all


Best regards,

Patrick

Lars Eirik R

Sunday 28 November 2010 4:17:15 pm

Hi Patrick.

After looking at the code and reinvestigating my needs i was able to solve this..

It turned out that i actually need to find all reverse_related_objects for each of my requested_objects, not the datamap. By iterating over the reversel_related objects i was able to get their datamap and consequently updated their related_object list with the updated keywords:)

Modifying your code i was able to fix this issue of mine.

So now i probably need to just have this routine run after each fo my topics have been updated. This will make it possible to run the workflow only after an object has been updated.

Simon Boyer

Friday 12 August 2011 1:12:49 am

Hi,

There is a workflow to execute after publish a related object, written from your work :

This workflow updates and re-indexes reverse related objects of modified node (ezfind+solr)

 <?php

require_once( 'kernel/common/template.php' );

class orUpdateType  extends eZWorkflowEventType
{
    const WORKFLOW_TYPE_STRING = "orupdate";
    const HTML_CONTENT_TYPE = 'text/html';

    var $site_ini;

    function __construct()
    {
        $this->eZWorkflowEventType( self::WORKFLOW_TYPE_STRING, ezpI18n::tr( 'workflow/event', 'Objects Relation Update' ) );
        $this->setTriggerTypes( array( 'content' => array( 'publish' => array( 'after') ) ) );
        $this->site_ini = eZIni::instance('site.ini');
    }


    function execute( $process, $event )
    {

        $parameters = $process->attribute( 'parameter_list' );
        $relateds_objects = eZContentFunctionCollection::fetchReverseRelatedObjects( $parameters['object_id']  , '', true, true);

        foreach($relateds_objects['result'] as $attributeId => $object_list) {
            $attribut = eZContentFunctionCollection::fetchClassAttribute($attributeId);
            $attribut = $attribut['result'];
    
            foreach($object_list as $objet) {
                
                $data_map = $objet->attribute( 'data_map' );
            
                // get the attribute
                $rel_attr = $data_map[ $attribut->Identifier ];
                $rel_attr_content = $rel_attr->Content();
                
                // store the object ids
                $rel_attr_obj_ids = array();
                foreach( $rel_attr_content[ 'relation_list' ] as $relObject )
                {
                    $rel_attr_obj_ids[] = $relObject[ 'contentobject_id' ];
                }
            
                // init new objectrelation attribute
                $newRelationList = new eZObjectRelationListType();
             
                // prepare the value to use with toString ("123-34657-58756"blunk.gif Emoticon
                $newRelationListString = implode( "-", $rel_attr_obj_ids );
             
                // use toString method to set the value and store the attribute
                $newRelationList->fromString( $rel_attr, $newRelationListString );
                $rel_attr->store();
                
                eZContentOperationCollection::registerSearchObject( $objet->attribute('id'), false );
                
            }
        }

        return eZWorkflowType::STATUS_ACCEPTED;
    }

}

eZWorkflowEventType::registerEventType( orUpdateType::WORKFLOW_TYPE_STRING, 'orUpdateType' );

?>

--
Developer at Open Wide

Powered by eZ Publish™ CMS Open Source Web Content Management. Copyright © 1999-2014 eZ Systems AS (except where otherwise noted). All rights reserved.