The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

OpenInteract2::ResultsManage - Save and retrieve generic search results

SYNOPSIS

 use OpenInteract2::ResultsManage;
 
 # Basic usage
 
 ... perform search ...
 
 my $results = OpenInteract2::ResultsManage->new();
 $results->save( \@id_list );
 $request->session->{this_search_id} = $results->{search_id};
 
 ... another request from this user ...
 
 my $results = OpenInteract2::ResultsManage->new({
                              search_id => $request->session->{this_search_id} });
 my $result_list = $results->retrieve();
 
 # Use with paged results
 
 my $results = OpenInteract2::ResultsManage->new();
 $results->save( \@id_list );
 $request->session->{this_search_id} = $results->{search_id};
 my $page_num = $R->apache->param( 'pagenum' );
 my ( $min, $max ) = $results->find_page_boundaries( $page_num, $HITS_PER_PAGE );
 my ( $results, $total_count ) = $results->retrieve({ min => $min, max => $max } );
 my $total_pages = $results->find_total_page_count( $HITS_PER_PAGE );
 my $total_hits = $results->{num_records};
 
 # Can now print "Page $page_num of $total_pages" or you
 # can pass this information to the template and use the
 # 'page_count' component and pass it 'total_pages',
 # 'current_pagenum', and a 'url' to get back to this page:
 
 [%- PROCESS page_count( total_pages     = 5,
                         current_pagenum = 3,
                         url             = url ) -%]
 
 Displays:
 
 Page [<<] [1] [2] 3 [4] [5] [>>]
 
 (Where the items enclosed by '[]' are links.)

DESCRIPTION

This class has methods to enable you to easily create paged result lists. This includes saving your results to disk, retrieving them easily and some simple calculation functions for page number determination.

PUBLIC METHODS

The following methods are public and available for OpenInteract application developers.

save( $stuff_to_save, \%params )

Saves a list of things to be retrieved later. The $stuff_to_save can be an arrayref of ID values (simple scalars), an arrayref of SPOPS objects, or an SPOPS::Iterator implementation all primed and ready to go. If objects are passed in via a list or an iterator, we call ->id() on each to get the ID value to save.

If objects are used, we also query each one for its class and save that information in the search results. Whether you have a homogenous resultset or not affects the return values. If it is a homogenous resultset we note the class for all objects in the search results metadata, which is saved in a separate file from the results themselves. This enables us to create an iterator from the results if needed.

Parameters:

  • class ($) (optional)

    You can force all the IDs passed in to be of a particular class.

  • extra (\@) (optional)

    Each item represents extra information to save along with each result. Each item must be either a scalar (which saves one extra item) or an arrayref (which saves a number of extra items).

  • extra_name (\@) (optional)

    If you specify extra information you need to give each one a name.

Returns: an ID you can use to retrieve the search results using the retrieve() or retrieve_iterator() methods. If you misplace the ID, you cannot get the search results back.

Side effects: the ID returned is also saved in the 'search_id' key of the object itself.

Example:

 my $results = OpenInteract2::ResultsManage->new();
 my $search_id = $results->save({ \@results,
                                  { force_mixed => 1,
                                    extra       => \@extra_info,
                                    extra_name  => [ 'hit_count', 'weight' ] });

The following parameters are set in the object after a successful results save:

 search_id
 num_records

Returns: the ID of the search just saved.

retrieve( $search_id, \%params )

Retrieve previously saved search results using the parameter 'search_id' which should be set on initialization or before this method is run.

Parameters:

  • min: Where we should start grabbing the results. Generally used if you are using a paged results scheme, (page 1 is 1 - 25, page 2 26 - 50, etc.). (Can be set at object creation.)

  • max: Where should we stop grabbing the results. See min. (Can be set at object creation.)

Returns:

  • In list context: an array with the first element an arrayref of the results (or IDs of the results), the second element an arrayref of the classes used in the results, the third element being the total number of items saved. (The total number of items can be helpful when creating pagecounts.)

  • In scalar context: an arrayref of the results.

Note: The interface for this method may change, and we might split apart the different return results into two methods (particularly whether classes are involved).

Also sets the object parameters:

'num_records' - total number of results in the original search

'date' - date the search was run

'num_extra' - number of 'extra' records saved

'extra_name' (\@) - list of fields matching extra values saved

retrieve_iterator( $search_id, \%params )

Retrieves an iterator to walk the results. You can use min/max to pre-separate or you can simply grab all the results and screen them out yourself.

Parameters: same as retrieve()

get_metadata( $search_id )

Fetch metadata only about a search. Returns a hashref with the following keys:

  • time - results storage time in epoch seconds

  • date - results storage time in human-readable format

  • num_records - number of records stored

  • filename - name of file (only the filename)

  • directory -

find_total_page_count( $records_per_page, [ $num_records ] )

If called as an object then use 'num_records' property of object. If 'num_records' is not in the object, or if you call this as a class method, then we use the second parameter for the total number of records.

Returns: Number of pages required to display $num_records at $records_per_page.

Example:

 my $page_count = $class->find_total_page_count( 289, 25 );
 # $page_count = 11
 
 my $page_count = $class->find_total_page_count( 289, 75 );
 # $page_count = 4

find_page_boundaries( $page_number, $records_per_page )

Returns: An array with the floor and ceiling values to display the given page with $records_per_page on the page.

Example:

 my ( $min, $max ) = $class->find_page_boundaries( 3, 75 );
 # $min is 226, $max is 300

 my ( $min, $max ) = $class->find_page_boundaries( 12, 25 );
 # min is 301, $max is 325

INTERNAL METHODS

_build_results_filename()

generate_search_id()

_lock_results()

_unlock_results()

_clear_results()

_retrieve_raw_results()

DATA FORMAT

Here is an example of a saved resultset. This one happens to be generated by the OpenInteract2::FullText module.

 Thu Jul 12 17:19:05 2001-->3-->-->1-->fulltext_score
 -->3d5676e0af1f1cc6b539fb08a5ee67b7-->2
 -->c3d72c3c568d99a796b23e8efc75c00f-->1
 -->8f10f3a91c3f10c876805ab1d76e1b94-->1

Here are all the pieces:

First, the separator is -->. This is configurable in this module.

Second, the first line has:

  • Thu Jul 12 17:19:05 2001

    The date the search was originally run.

  • 3

    The number of items in the entire search resultset.

  • (empty)

    If it were filled it would be either a classname (e.g., 'MySite::User') or the keyword 'MIXED' which tells this class that the results are of multiple classes.

  • 1

    The number of 'extra' fields.

  • fulltext_score

    The name of the first 'extra' field. If there wore than one extra field they would be separated with commas.

Third, the second and remaining line have three pieces:

  • (empty)

    The class name for this result. Since these IDs are not from a class, there is no class name.

    3d5676e0af1f1cc6b539fb08a5ee67b7

    The main value returned, also the ID of the object returned that, when matched with the class name (first item) would be able to define an object to be fetched.

    2

    The first 'extra' value. Successive 'extra' values are separated by '-->' like the other fields.

BUGS

None known, although the API may change in the near future.

TO DO

Review API

The API is currently unstable but should solidify quickly as we get more use out of this module.

 - Keep 'mixed' stuff in there, or maybe always treat the resultset as
 potentially heterogeneous objects?

 - Test with saving different types of non-object data as well as
 objects and see if the usage holds up (including with the
 ResultsIterator).

COPYRIGHT

Copyright (c) 2001-2004 Chris Winters. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHORS

Chris Winters <chris@cwinters.com>