diff --git a/config/vufind/searches.ini b/config/vufind/searches.ini
index f6fbd8eff1999c09437556dcea46e22b63e2ae18..ce6461f530995a19d6ce430198226f80544c95cc 100644
--- a/config/vufind/searches.ini
+++ b/config/vufind/searches.ini
@@ -191,6 +191,25 @@ CallNumber = callnumber
 ; OpenLibrarySubjectsDeferred:[GET parameter]:[limit]:[date filter]:[Subject types]
 ;       The same as OpenLibrarySubjects but uses AJAX to make the API calls after the
 ;           main result set has loaded
+; RandomRecommend:[backend]:[limit]:[display mode]:[random mode]:[minimumset]
+;        :[facet1]:[facetvalue1]:[facet2]:[facetvalue2]:...:[facet-n]:[facetvalue-n]
+;       This module offers random records either from the whole backend or within
+;       the current resultset.
+;       [backend] is the name of the search backend currently in use,
+;       which will help with accurate analysis (default = Solr)
+;       [limit] is the number of records to display (default = 10)
+;       [display mode] determines how the records are displayed. Valid values are
+;       "standard" (for a basic display including titles and authors), 
+;       "images" for just images or "mixed" for both. (default = standard)
+;       [random mode] determines if the records are selected from the entire backend
+;       or from the current result set. Valid values are "retain" to limit results 
+;       to the current result set or "disregard" to use the entire backend. 
+;       (default = retain)
+;       [minimumset] is the minimum result set count required to display random items,
+;       0 = no minimum required. This setting can be used to prevent random items
+;       displaying in a small result set. (default = 0)
+;       [facet-n] A facet to apply to the random selection
+;       [facetvalue-n] The facet value to apply to the random selection 
 ; SideFacets:[regular facet section]:[checkbox facet section]:[ini name]
 ;       Display the specified facets, where [ini name] is the name of an ini file
 ;       in your config directory (defaults to "facets" if not supplied),
diff --git a/languages/en.ini b/languages/en.ini
index 4206b2a7b55bbdf3175ece329addf06f2394b334..376fe0f6e2bdf9f0fda27fc3b505a2931f25934b 100644
--- a/languages/en.ini
+++ b/languages/en.ini
@@ -644,6 +644,7 @@ QR Code = "QR Code"
 qrcode_hide = "Hide QR Code"
 qrcode_show = "Show QR Code"
 query time = "query time"
+random_recommendation_title = "Random items from your results"
 Range = Range
 Range slider = "Range slider"
 Read the full review online... = "Read the full review online..."
diff --git a/module/VuFind/config/module.config.php b/module/VuFind/config/module.config.php
index 56b8951af34882957ae925512aa09ac1f5b6babc..9b0b83fa2428352a0d938b05a6e84deaafcdc4cd 100644
--- a/module/VuFind/config/module.config.php
+++ b/module/VuFind/config/module.config.php
@@ -323,6 +323,7 @@ $config = array(
                     'expandfacets' => 'VuFind\Recommend\Factory::getExpandFacets',
                     'favoritefacets' => 'VuFind\Recommend\Factory::getFavoriteFacets',
                     'sidefacets' => 'VuFind\Recommend\Factory::getSideFacets',
+                    'randomrecommend' => 'VuFind\Recommend\Factory::getRandomRecommend',
                     'summonbestbets' => 'VuFind\Recommend\Factory::getSummonBestBets',
                     'summondatabases' => 'VuFind\Recommend\Factory::getSummonDatabases',
                     'summonresults' => 'VuFind\Recommend\Factory::getSummonResults',
diff --git a/module/VuFind/src/VuFind/Recommend/Factory.php b/module/VuFind/src/VuFind/Recommend/Factory.php
index 94736406f4ec6f38af72f9c7652808ad3d5dc645..5ff8601054d234cb7ab51ebbd46923ef5fa0099e 100644
--- a/module/VuFind/src/VuFind/Recommend/Factory.php
+++ b/module/VuFind/src/VuFind/Recommend/Factory.php
@@ -157,6 +157,21 @@ class Factory
         );
     }
 
+    /**
+     * Factory for Random Recommendations.
+     *
+     * @param ServiceManager $sm Service manager.
+     *
+     * @return RandomRecommend
+     */
+    public static function getRandomRecommend(ServiceManager $sm)
+    {
+        return new RandomRecommend(
+            $sm->getServiceLocator()->get('VuFind\Search'),
+            $sm->getServiceLocator()->get('VuFind\SearchParamsPluginManager')
+        );
+    }
+
     /**
      * Factory for SideFacets module.
      *
diff --git a/module/VuFind/src/VuFind/Recommend/RandomRecommend.php b/module/VuFind/src/VuFind/Recommend/RandomRecommend.php
new file mode 100644
index 0000000000000000000000000000000000000000..bfd23dc4599310678f5f8c3aeabdad6931b82335
--- /dev/null
+++ b/module/VuFind/src/VuFind/Recommend/RandomRecommend.php
@@ -0,0 +1,224 @@
+<?php
+/**
+ * RandomRecommend Recommendations Module
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2012.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Recommendations
+ * @author   Luke O'Sullivan (Swansea University)
+ * <vufind-tech@lists.sourceforge.net>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://www.vufind.org  Main Page
+ */
+namespace VuFind\Recommend;
+
+use VuFindSearch\Query\Query,
+    VuFindSearch\ParamBag;
+
+/**
+ * RandomRecommend Module
+ *
+ * This class provides random recommendations based on the Solr random field
+ *
+ * @category VuFind2
+ * @package  Recommendations
+ * @author   Luke O'Sullivan (Swansea University)
+ * <vufind-tech@lists.sourceforge.net>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://www.vufind.org  Main Page
+ */
+class RandomRecommend implements RecommendInterface
+{
+    /**
+     * Results
+     *
+     * @var array
+     */
+    protected $results;
+
+    /**
+     * Results Limit
+     *
+     * @var number
+     */
+    protected $limit;
+
+    /**
+     * Display Mode
+     *
+     * @var string
+     */
+    protected $displayMode;
+
+    /**
+     * Mode
+     *
+     * @var string
+     */
+    protected $mode;
+
+    /**
+     * Result Set Minimum
+     *
+     * @var number
+     */
+    protected $minimum;
+
+    /**
+     * Filters
+     *
+     * @var array
+     */
+    protected $filters = array();
+
+    /**
+     * Settings from configuration
+     *
+     * @var string
+     */
+    protected $settings;
+
+    /**
+     * Search Service
+     *
+     * @var \VuFindSearch\Service
+     */
+    protected $searchService;
+
+    /**
+     * Params manager
+     *
+     * @var \VuFind\Search\Params\PluginManager
+     */
+    protected $paramManager;
+
+    /**
+     * Constructor
+     *
+     * @param \VuFindSearch\Service               $searchService VuFind Search Serive
+     * @param \VuFind\Search\Params\PluginManager $paramManager  Params manager
+     */
+    public function __construct(\VuFindSearch\Service $searchService,
+        \VuFind\Search\Params\PluginManager $paramManager
+    ) {
+        $this->searchService = $searchService;
+        $this->paramManager = $paramManager;
+    }
+
+    /**
+     * setConfig
+     *
+     * Store the configuration of the recommendation module.
+     *
+     * @param string $settings Settings from searches.ini.
+     *
+     * @return void
+     */
+    public function setConfig($settings)
+    {
+        // Save the basic parameters:
+        $this->settings = $settings;
+
+        // Parse the additional settings:
+        $settings = explode(':', $settings);
+        $this->backend = !empty($settings[0]) ? $settings[0] : 'Solr';
+        $this->limit = isset($settings[1]) && !empty($settings[1])
+            ? $settings[1] : 10;
+        $this->displayMode = isset($settings[2]) && !empty($settings[2])
+            ? $settings[2] : "standard";
+        $this->mode = !empty($settings[3]) ? $settings[3] : 'retain';
+        $this->minimum = !empty($settings[4]) ? $settings[4] : 0;
+
+        // all other params are filters and there values respectively
+        for ($i = 5; $i < count($settings); $i += 2) {
+            if (isset($settings[$i+1])) {
+                $this->filters[] = $settings[$i] . ':' . $settings[$i + 1];
+            }
+        }
+    }
+
+    /**
+     * init
+     *
+     * Called at the end of the Search Params objects' initFromRequest() method.
+     * This method is responsible for setting search parameters needed by the
+     * recommendation module and for reading any existing search parameters that may
+     * be needed.
+     *
+     * @param \VuFind\Search\Base\Params $params  Search parameter object
+     * @param \Zend\StdLib\Parameters    $request Parameter object representing user
+     * request.
+     *
+     * @return void
+    */
+    public function init($params, $request)
+    {
+        if ("retain" !== $this->mode) {
+            $randomParams = $this->paramManager->get($params->getSearchClassId());
+        } else {
+            $randomParams = clone $params;
+        }
+        foreach ($this->filters as $filter) {
+            $randomParams->addFilter($filter);
+        }
+        $query = $randomParams->getQuery();
+        $paramBag = $randomParams->getBackendParameters();
+        $this->results = $this->searchService->random(
+            $this->backend, $query, $this->limit, $paramBag
+        )->getRecords();
+    }
+
+    /**
+     * process
+     *
+     * Called after the Search Results object has performed its main search.  This
+     * may be used to extract necessary information from the Search Results object
+     * or to perform completely unrelated processing.
+     *
+     * @param \VuFind\Search\Base\Results $results Search results object
+     *
+     * @return void
+    */
+    public function process($results)
+    {
+    }
+
+    /**
+     * Get Results
+     *
+     * @return array
+     */
+    public function getResults()
+    {
+        if (count($this->results) < $this->minimum) {
+            return array();
+        }
+        return $this->results;
+    }
+
+    /**
+     * Get Display Mode
+     *
+     * @return string
+     */
+    public function getDisplayMode()
+    {
+        return $this->displayMode;
+    }
+}
diff --git a/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php b/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9bffc41c3098a363d6be2ca7eb5615f737b1c44f
--- /dev/null
+++ b/module/VuFind/tests/unit-tests/src/VuFindTest/Recommend/RandomRecommendTest.php
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Random Recommend tests.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Tests
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/vufind2:unit_tests Wiki
+ */
+
+namespace VuFindTest\Recommend;
+
+use VuFind\Recommend\RandomRecommend as Random;
+use VuFindTest\Unit\TestCase as TestCase;
+
+/**
+ * Random Recommend tests.
+ *
+ * @category VuFind2
+ * @package  Tests
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org/wiki/vufind2:unit_tests Wiki
+ */
+class RandomRecommendTest extends TestCase
+{
+    /**
+     * Standard setup method.
+     *
+     * @return void
+     */
+    public function setup()
+    {
+        $this->recommend = new Random(
+            $this->getMock('VuFindSearch\Service'),
+            $this->getMock('VuFind\Search\Params\PluginManager')
+        );
+    }
+
+    /**
+     * Test load
+     *
+     * @return void
+     */
+    public function testCanSetDisplayMode()
+    {
+        $this->recommend->setConfig("Solr:10:disregard");
+        $this->assertEquals("disregard", $this->recommend->getDisplayMode());
+    }
+}
diff --git a/module/VuFindSearch/src/VuFindSearch/Backend/Solr/Backend.php b/module/VuFindSearch/src/VuFindSearch/Backend/Solr/Backend.php
index e1a5050a6d2e4e1afc39c268d13d3b57248c0c2c..80d583bcb6f411c4f868edd1f67bf98d578fb369 100644
--- a/module/VuFindSearch/src/VuFindSearch/Backend/Solr/Backend.php
+++ b/module/VuFindSearch/src/VuFindSearch/Backend/Solr/Backend.php
@@ -40,6 +40,7 @@ use VuFindSearch\Backend\Solr\Response\Json\Terms;
 use VuFindSearch\Backend\AbstractBackend;
 use VuFindSearch\Feature\SimilarInterface;
 use VuFindSearch\Feature\RetrieveBatchInterface;
+use VuFindSearch\Feature\RandomInterface;
 
 use VuFindSearch\Backend\Exception\BackendException;
 use VuFindSearch\Backend\Exception\RemoteErrorException;
@@ -56,7 +57,7 @@ use VuFindSearch\Exception\InvalidArgumentException;
  * @link     http://vufind.org
  */
 class Backend extends AbstractBackend
-    implements SimilarInterface, RetrieveBatchInterface
+    implements SimilarInterface, RetrieveBatchInterface, RandomInterface
 {
     /**
      * Connector.
@@ -111,6 +112,28 @@ class Backend extends AbstractBackend
         return $collection;
     }
 
+    /**
+     * Get Random records
+     *
+     * @param AbstractQuery $query  Search query
+     * @param integer       $limit  Search limit
+     * @param ParamBag      $params Search backend parameters
+     *
+     * @return RecordCollectionInterface
+     */
+    public function random(
+        AbstractQuery $query, $limit, ParamBag $params = null
+    ) {
+        $params = $params ?: new ParamBag();
+        $this->injectResponseWriter($params);
+
+        $random = rand(0, 1000000);
+        $sort = "{$random}_random asc";
+        $params->set('sort', $sort);
+
+        return $this->search($query, 0, $limit, $params);
+    }
+
     /**
      * Retrieve a single document.
      *
diff --git a/module/VuFindSearch/src/VuFindSearch/Feature/RandomInterface.php b/module/VuFindSearch/src/VuFindSearch/Feature/RandomInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..4c0810a2a8f1f7a8bdf7d72abbd05a3391ca41fe
--- /dev/null
+++ b/module/VuFindSearch/src/VuFindSearch/Feature/RandomInterface.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * Random record retrieval feature interface definition.
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  Search
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org
+ */
+
+namespace VuFindSearch\Feature;
+
+use VuFindSearch\ParamBag;
+use VuFindSearch\Query\AbstractQuery;
+
+/**
+ * Random record retrieval feature interface definition.
+ *
+ * @category VuFind2
+ * @package  Search
+ * @author   Luke O'Sullivan <l.osullivan@swansea.ac.uk>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org
+ */
+interface RandomInterface
+{
+    /**
+     * Return random records.
+     *
+     * @param AbstractQuery $query  Search query
+     * @param integer       $limit  Search limit
+     * @param ParamBag      $params Search backend parameters
+     *
+     * @return \VuFindSearch\Response\RecordCollectionInterface
+     */
+    public function random(
+        AbstractQuery $query, $limit, ParamBag $params = null
+    );
+}
diff --git a/module/VuFindSearch/src/VuFindSearch/Response/AbstractRecordCollection.php b/module/VuFindSearch/src/VuFindSearch/Response/AbstractRecordCollection.php
index cf8e94dd262f3c07a2160b35486be64f853cd7d6..fbbcb540c0b9e14ffd6070b35bb5f9a0f339727a 100644
--- a/module/VuFindSearch/src/VuFindSearch/Response/AbstractRecordCollection.php
+++ b/module/VuFindSearch/src/VuFindSearch/Response/AbstractRecordCollection.php
@@ -81,6 +81,16 @@ abstract class AbstractRecordCollection implements RecordCollectionInterface
         return $this->records;
     }
 
+    /**
+     * Shuffles records.
+     *
+     * @return bool
+     */
+    public function shuffle()
+    {
+        return shuffle($this->records);
+    }
+
     /**
      * Return first record in response.
      *
diff --git a/module/VuFindSearch/src/VuFindSearch/Service.php b/module/VuFindSearch/src/VuFindSearch/Service.php
index 8108e4186864c0120ee0b8eca9aa7ff59904d10e..1618c7aaa62d513b34df2b8bd944fd5381404088 100644
--- a/module/VuFindSearch/src/VuFindSearch/Service.php
+++ b/module/VuFindSearch/src/VuFindSearch/Service.php
@@ -31,6 +31,7 @@ namespace VuFindSearch;
 
 use VuFindSearch\Backend\BackendInterface;
 use VuFindSearch\Feature\RetrieveBatchInterface;
+use VuFindSearch\Feature\RandomInterface;
 use VuFindSearch\Backend\Exception\BackendException;
 
 use Zend\EventManager\EventManagerInterface;
@@ -190,6 +191,86 @@ class Service
         return $response;
     }
 
+    /**
+     * Retrieve a random batch of records.
+     *
+     * @param string              $backend Search backend identifier
+     * @param Query\AbstractQuery $query   Search query
+     * @param integer             $limit   Search limit
+     * @param ParamBag            $params  Search backend parameters
+     *
+     * @return ResponseInterface
+     */
+    public function random($backend, $query, $limit = 20, $params = null)
+    {
+        $params  = $params ?: new ParamBag();
+        $backendString = $backend;
+        $context = __FUNCTION__;
+        $args = compact('backend', 'query', 'limit', 'params', 'context');
+        $backend = $this->resolve($backend, $args);
+        $args['backend_instance'] = $backend;
+
+        $this->triggerPre($backend, $args);
+
+        // If the backend implements the RetrieveRandomInterface, we can load
+        // all the records at once; otherwise, we need to load them one at a
+        // time and aggregate them:
+        if ($backend instanceof RandomInterface) {
+            try {
+                $response = $backend->random($query, $limit, $params);
+            } catch (BackendException $e) {
+                $this->triggerError($e, $args);
+                throw $e;
+            }
+        } else {
+            // offset/limit of 0 - we don't need records, just count
+            try {
+                $results = $backend->search($query, 0, 0, $params);
+            } catch (BackendException $e) {
+                $this->triggerError($e, $args);
+                throw $e;
+            }
+            $total_records = $results->getTotal();
+
+            if (0 === $total_records) {
+                // Empty result? Send back as-is:
+                $response = $results;
+            } elseif ($total_records < $limit) {
+                // Result set smaller than limit? Get everything and shuffle:
+                try {
+                     $response = $backend->search($query, 0, $limit, $params);
+                } catch (BackendException $e) {
+                    $this->triggerError($e, $args);
+                    throw $e;
+                }
+                $response->shuffle();
+            } else {
+                // Default case: retrieve n random records:
+                $response = false;
+                $retrievedIndexes = array();
+                $retrievedRecordIds = array();
+                for ($i = 0; $i < $limit; $i++) {
+                    $nextIndex = rand(0, $total_records - 1);
+                    while (in_array($nextIndex, $retrievedIndexes)) {
+                        // avoid duplicate records
+                        $nextIndex = rand(0, $total_records - 1);
+                    }
+                    $retrievedIndexes[] = $nextIndex;
+                    $currentBatch = $backend->search(
+                        $query, $nextIndex, 1, $params
+                    );
+                    if (!$response) {
+                        $response = $currentBatch;
+                    } else if ($record = $currentBatch->first()) {
+                        $response->add($record);
+                    }
+                }
+            }
+        }
+        $this->triggerPost($response, $args);
+        return $response;
+    }
+
     /**
      * Return similar records.
      *
diff --git a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php
index 058e30aa0104bc2cb6253652558dd1e8aff8898b..b3b0f15ebff1e4513b7e3c8eceffdec6a5f0d7dc 100644
--- a/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php
+++ b/module/VuFindSearch/tests/unit-tests/src/VuFindTest/SearchServiceTest.php
@@ -34,6 +34,7 @@ use VuFindSearch\ParamBag;
 use VuFindSearch\Backend\BackendInterface;
 use VuFindSearch\Backend\Exception\BackendException;
 use VuFindSearch\Feature\RetrieveBatchInterface;
+use VuFindSearch\Feature\RandomInterface;
 use VuFindSearch\Query\Query;
 use VuFindSearch\Response\AbstractRecordCollection;
 
@@ -240,6 +241,235 @@ class SearchServiceTest extends TestCase
         $service->retrieveBatch('foo', array('bar'), $params);
     }
 
+    /**
+     * Test random (with RandomInterface).
+     *
+     * @return void
+     */
+    public function testRandomInterface()
+    {
+        // Use a special backend for this test...
+        $this->backend = $this->getMock('VuFindTest\TestClassForRandomInterface');
+
+        $service = $this->getService();
+        $backend = $this->getBackend();
+        $response = $this->getRecordCollection();
+        $params = new ParamBag(array('x' => 'y'));
+        $query = new Query('test');
+
+        $backend->expects($this->once())->method('random')
+            ->with(
+                 $this->equalTo($query),
+                 $this->equalTo("10"),
+                 $this->equalTo($params)
+             )->will($this->returnValue($response)
+        );
+        $em = $service->getEventManager();
+        $em->expects($this->at(0))->method('trigger')
+            ->with($this->equalTo('pre'), $this->equalTo($backend));
+        $em->expects($this->at(1))->method('trigger')
+            ->with($this->equalTo('post'), $this->equalTo($response));
+        $service->random('foo', $query, "10", $params);
+
+        // Put the backend back to the default:
+        unset($this->backend);
+    }
+
+    /**
+     * Test random (with RandomInterface) exception.
+     *
+     * @return void
+     * @expectedException VuFindSearch\Backend\Exception\BackendException
+     * @expectedExceptionMessage test
+     */
+    public function testRandomInterfaceWithException()
+    {
+        // Use a special backend for this test...
+        $this->backend = $this->getMock('VuFindTest\TestClassForRandomInterface');
+
+        $service = $this->getService();
+        $backend = $this->getBackend();
+        $exception = new BackendException('test');
+        $params = new ParamBag(array('x' => 'y'));
+        $query = new Query('test');
+
+        $backend->expects($this->once())->method('random')
+        ->with(
+            $this->equalTo($query),
+            $this->equalTo("10"),
+            $this->equalTo($params)
+        )->will($this->throwException($exception));
+
+        $em = $service->getEventManager();
+        $em->expects($this->at(0))->method('trigger')
+            ->with($this->equalTo('pre'), $this->equalTo($backend));
+        $em->expects($this->at(1))->method('trigger')
+            ->with($this->equalTo('error'), $this->equalTo($exception));
+        $service->random('foo', $query, "10", $params);
+
+        // Put the backend back to the default:
+        unset($this->backend);
+    }
+
+    /**
+     * Test random (without RandomInterface).
+     *
+     * @return void
+     */
+    public function testRandomNoInterface()
+    {
+        $limit = 10;
+        $total = 20;
+        $service = $this->getService();
+        $backend = $this->getBackend();
+        $responseForZero = $this->getRecordCollection();
+
+        $params = new ParamBag(array('x' => 'y'));
+        $query = new Query('test');
+
+        // First Search Grabs 0 records but uses get total method
+        $backend->expects($this->at(0))->method('search')
+        ->with(
+            $this->equalTo($query),
+            $this->equalTo("0"),
+            $this->equalTo("0"),
+            $this->equalTo($params)
+        )->will($this->returnValue($responseForZero));
+
+        $responseForZero->expects($this->once())->method('getTotal')
+            ->will($this->returnValue($total));
+
+        for ($i=1; $i<$limit+1; $i++) {
+            $response = $this->getRecordCollection();
+            $response->expects($this->any())->method('first')
+                ->will($this->returnValue($this->getMock('VuFindSearch\Response\RecordInterface')));
+            $backend->expects($this->at($i))->method('search')
+                ->with(
+                    $this->equalTo($query),
+                    $this->anything(),
+                    $this->equalTo("1"),
+                    $this->equalTo($params)
+                )->will($this->returnValue($response)
+            );
+        }
+
+        $em = $service->getEventManager();
+        $em->expects($this->at(0))->method('trigger')
+            ->with($this->equalTo('pre'), $this->equalTo($backend));
+        $em->expects($this->at(1))->method('trigger')
+            ->with($this->equalTo('post'), $this->anything());
+        $service->random('foo', $query, $limit, $params);
+    }
+
+    /**
+     * Test random (without RandomInterface).
+     *
+     * @return void
+     */
+    public function testRandomNoInterfaceWithNoResults()
+    {
+        $limit = 10;
+        $total = 0;
+        $service = $this->getService();
+        $backend = $this->getBackend();
+        $responseForZero = $this->getRecordCollection();
+
+        $params = new ParamBag(array('x' => 'y'));
+        $query = new Query('test');
+
+        // First Search Grabs 0 records but uses get total method
+        // This should only be called once as the total results returned is 0
+        $backend->expects($this->once())->method('search')
+            ->with(
+                $this->equalTo($query),
+                $this->equalTo("0"),
+                $this->equalTo("0"),
+                $this->equalTo($params)
+            )->will($this->returnValue($responseForZero));
+
+        $responseForZero->expects($this->once())->method('getTotal')
+            ->will($this->returnValue($total));
+
+        $em = $service->getEventManager();
+        $em->expects($this->at(0))->method('trigger')
+            ->with($this->equalTo('pre'), $this->equalTo($backend));
+        $em->expects($this->at(1))->method('trigger')
+            ->with($this->equalTo('post'), $this->equalTo($responseForZero));
+        $service->random('foo', $query, $limit, $params);
+    }
+
+    /**
+     * Test random (without RandomInterface).
+     *
+     * @return void
+     */
+    public function testRandomNoInterfaceWithLessResultsThanLimit()
+    {
+        $limit = 10;
+        $total = 5;
+        $service = $this->getService();
+        $backend = $this->getBackend();
+        $responseForZero = $this->getRecordCollection();
+        $response = $this->getRecordCollection();
+
+        $params = new ParamBag(array('x' => 'y'));
+        $query = new Query('test');
+
+        // First Search Grabs 0 records but uses get total method
+        $backend->expects($this->at(0))->method('search')
+            ->with(
+                $this->equalTo($query),
+                $this->equalTo("0"),
+                $this->equalTo("0"),
+                $this->equalTo($params)
+            )->will($this->returnValue($responseForZero));
+
+        $responseForZero->expects($this->once())->method('getTotal')
+            ->will($this->returnValue($total));
+
+        // Second search grabs all the records and calls shuffle
+        $backend->expects($this->at(1))->method('search')
+            ->with(
+                    $this->equalTo($query),
+                    $this->equalTo("0"),
+                    $this->equalTo($limit),
+                    $this->equalTo($params)
+            )->will($this->returnValue($response));
+        $response->expects($this->once())->method('shuffle');
+
+        $em = $service->getEventManager();
+        $em->expects($this->at(0))->method('trigger')
+            ->with($this->equalTo('pre'), $this->equalTo($backend));
+        $em->expects($this->at(1))->method('trigger')
+            ->with($this->equalTo('post'), $this->equalTo($responseForZero));
+        $service->random('foo', $query, $limit, $params);
+    }
+
+    /**
+     * Test random (without RandomInterface) exception.
+     *
+     * @return void
+     * @expectedException VuFindSearch\Backend\Exception\BackendException
+     * @expectedExceptionMessage test
+     */
+    public function testRandomNoInterfaceWithException()
+    {
+        $service = $this->getService();
+        $backend = $this->getBackend();
+        $exception = new BackendException('test');
+        $params = new ParamBag(array('x' => 'y'));
+        $query = new Query('test');
+
+        $backend->expects($this->once())->method('search')
+            ->will($this->throwException($exception));
+        $em = $service->getEventManager();
+        $em->expects($this->at(0))->method('trigger')
+            ->with($this->equalTo('pre'), $this->equalTo($backend));
+        $em->expects($this->at(1))->method('trigger')
+            ->with($this->equalTo('error'), $this->equalTo($exception));
+        $service->random('foo', $query, "10", $params);
+    }
+
     /**
      * Test similar action.
      *
@@ -376,4 +606,13 @@ abstract class TestBackendClassForSimilar
     implements BackendInterface
 {
     abstract function similar();
+}
+
+/**
+ * Stub Class to test random interfaces.
+ */
+abstract class TestClassForRandomInterface
+implements BackendInterface, RandomInterface
+{
+
 }
\ No newline at end of file
diff --git a/solr/biblio/conf/schema.xml b/solr/biblio/conf/schema.xml
index abc8ee2e31daf4d1731e99664984d0269e8d9cf9..e2cec2509e7105fb355abd9521f86965025d9499 100644
--- a/solr/biblio/conf/schema.xml
+++ b/solr/biblio/conf/schema.xml
@@ -94,6 +94,7 @@
       </analyzer>
     </fieldType>
     <fieldType name="date" class="solr.TrieDateField" sortMissingLast="true" omitNorms="true" precisionStep="6"/>
+    <fieldType name="random" class="solr.RandomSortField" indexed="true" />
   </types>
  <fields>
    <!-- Required by Solr 4.x -->
@@ -216,6 +217,7 @@
    <dynamicField name="*_txtF_mv" type="textFacet" indexed="true" stored="true" multiValued="true"/>
    <dynamicField name="*_txtP" type="textProper" indexed="true" stored="true"/>
    <dynamicField name="*_txtP_mv" type="textProper" indexed="true" stored="true" multiValued="true"/>
+   <dynamicField name="*_random" type="random" />
  </fields>
  <uniqueKey>id</uniqueKey>
  <defaultSearchField>allfields</defaultSearchField>
diff --git a/themes/blueprint/css/styles.css b/themes/blueprint/css/styles.css
index dc15aacaf2dba11ce50f7d47e1930523ebef49e1..d0916b44f7c5f2d04357191151e755d76024ab2f 100644
--- a/themes/blueprint/css/styles.css
+++ b/themes/blueprint/css/styles.css
@@ -1126,6 +1126,31 @@ ul.similar li {
     padding-bottom:10px;
 }
 
+/** Random Items (results view) **/
+
+ul.random {
+    list-style: none;
+    padding: 0;
+    margin: 0px;
+    text-align:justified;
+}
+
+ul.random li {
+    padding-bottom:10px;
+}
+
+ul.random li img {
+    margin: 0 auto 1em auto;
+}
+
+ul.random.image, ul.random.mixed {
+    text-align: center;
+}
+
+ul.random.image li img {
+    margin: 0 auto;
+}
+
 /*********** Toolbar (Record View) ************/
 .toolbar {
     border-bottom:1px solid #eee;
diff --git a/themes/blueprint/templates/Recommend/RandomRecommend.phtml b/themes/blueprint/templates/Recommend/RandomRecommend.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..c66550b99471310ac21afc7b1c5add5f1b8ebd5c
--- /dev/null
+++ b/themes/blueprint/templates/Recommend/RandomRecommend.phtml
@@ -0,0 +1,55 @@
+<? $recommend = $this->recommend->getResults(); if (count($recommend)> 0): ?>
+
+  <div class="sidegroup">
+  <h4><?=$this->transEsc("random_recommendation_title")?></h4>
+  <ul class="random <?=$this->recommend->getDisplayMode()?>">
+    <? foreach ($recommend as $driver): ?>
+      <li>
+
+      <?if($this->recommend->getDisplayMode() === "images" || $this->recommend->getDisplayMode() === "mixed"):?>
+
+        <? /* Display thumbnail if appropriate: */ ?>
+        <? $smallThumb = $this->record($driver)->getThumbnail('small'); $mediumThumb = $this->record($driver)->getThumbnail('medium'); ?>
+        <? if ($smallThumb): ?>
+          <a href="<?=$this->recordLink()->getUrl($driver)?>">
+           <img alt="<?=$this->transEsc('Cover Image')?>" class="recordcover" src="<?=$this->escapeHtml($smallThumb);?>"/>
+          </a>
+        <?elseif($mediumThumb):?>
+          <a href="<?=$this->recordLink()->getUrl($driver)?>">
+            <img alt="<?=$this->transEsc('Cover Image')?>" class="recordcover" src="<?=$this->escapeHtml($mediumThumb);?>"/>
+          </a>
+        <? else: ?>
+          <img src="<?=$this->url('cover-unavailable')?>" class="recordcover" alt="<?=$this->transEsc('No Cover Image')?>"/>
+        <? endif; ?>
+
+      <?endif;?>
+
+       <?if($this->recommend->getDisplayMode() === "standard" || $this->recommend->getDisplayMode() === "mixed"):?>
+            <? $formats = $driver->getFormats(); $format = isset($formats[0]) ? $formats[0] : ''; ?>
+            <span class="<?=$this->record($driver)->getFormatClass($format)?>">
+            <a href="<?=$this->recordLink()->getUrl($driver)?>" class="title"><?
+              $summTitle = $driver->getTitle();
+              if (!empty($summTitle)) {
+                  echo $this->escapeHtml($this->truncate($summTitle, 180));
+              } else {
+                  echo $this->transEsc('Title not available');
+              }
+            ?></a>
+            </span>
+            <? $summAuthor = $driver->getPrimaryAuthor(); if (!empty($summAuthor)): ?>
+            <br />
+            <?=$this->transEsc('By')?>:
+            <a href="<?=$this->record($driver)->getLink('author', $summAuthor)?>">
+              <?=$this->escapeHtml($summAuthor)?>
+            </a>
+            <? endif; ?>
+            <? $summDate = $driver->getPublicationDates(); if (!empty($summDate)): ?>
+            <br/><?=$this->transEsc('Published')?>: (<?=$this->escapeHtml($summDate[0])?>)
+            <? endif; ?>
+         <?endif;?>
+        </li>
+      <? endforeach; ?>
+    </ul>
+
+  </div>
+<?endif;?>
diff --git a/themes/bootprint/css/bootprint-custom.css b/themes/bootprint/css/bootprint-custom.css
index 0bab11ff36ec6ead9c917c4fb214dd7018ee3a85..ccab26dcbe050728c0cd220aa2ef783feb747041 100644
--- a/themes/bootprint/css/bootprint-custom.css
+++ b/themes/bootprint/css/bootprint-custom.css
@@ -207,4 +207,29 @@ select, .btn:not(.btn-link){vertical-align:top}
 #custom_recaptcha_widget embed { display:none; }
 #custom_recaptcha_widget #recaptcha_image { border:1px solid #000;padding:6px;margin:1em 0; }
 #custom_recaptcha_widget #recaptcha_response_field { margin:0 .5em }
-#custom_recaptcha_widget > div > a { display:inline-block;float:left;margin:5px 10px 5px 0; }
\ No newline at end of file
+#custom_recaptcha_widget > div > a { display:inline-block;float:left;margin:5px 10px 5px 0; }
+
+/* --- Random Items (results view) --- */
+
+ul.random {
+    list-style: none;
+    padding: 0;
+    margin: 0px;
+    text-align:justified;
+}
+
+ul.random li {
+    padding-bottom:10px;
+}
+
+ul.random li img {
+    margin: 0 auto 1em auto;
+}
+
+ul.random.image, ul.random.mixed {
+    text-align: center;
+}
+
+ul.random.image li img {
+    margin: 0 auto;
+}
diff --git a/themes/bootstrap/templates/Recommend/RandomRecommend.phtml b/themes/bootstrap/templates/Recommend/RandomRecommend.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..66c5eba84e4203ee1eae0b455b4fe24c8445ce86
--- /dev/null
+++ b/themes/bootstrap/templates/Recommend/RandomRecommend.phtml
@@ -0,0 +1,49 @@
+<? $recommend = $this->recommend->getResults(); if (count($recommend)> 0): ?>
+  <h4><?=$this->transEsc("random_recommendation_title")?></h4>
+  <ul class="random <?=$this->recommend->getDisplayMode()?>">
+    <? foreach ($recommend as $driver): ?>
+      <li>
+
+      <?if($this->recommend->getDisplayMode() === "images" || $this->recommend->getDisplayMode() === "mixed"):?>
+
+        <? /* Display thumbnail if appropriate: */ ?>
+        <? $smallThumb = $this->record($driver)->getThumbnail('small'); $mediumThumb = $this->record($driver)->getThumbnail('medium'); ?>
+        <? if ($smallThumb): ?>
+          <a href="<?=$this->recordLink()->getUrl($driver)?>">
+           <img alt="<?=$this->transEsc('Cover Image')?>" src="<?=$this->escapeHtml($smallThumb);?>"/><br />
+          </a>
+        <?elseif($mediumThumb):?>
+          <a href="<?=$this->recordLink()->getUrl($driver)?>">
+            <img alt="<?=$this->transEsc('Cover Image')?>" src="<?=$this->escapeHtml($mediumThumb);?>"/><br />
+          </a>
+        <? else: ?>
+          <img src="<?=$this->url('cover-unavailable')?>" alt="<?=$this->transEsc('No Cover Image')?>"/><br />
+        <? endif; ?>
+
+      <?endif;?>
+
+     <?if($this->recommend->getDisplayMode() === "standard" || $this->recommend->getDisplayMode() === "mixed"):?>
+          <? $formats = $driver->getFormats(); $format = isset($formats[0]) ? $formats[0] : ''; ?>
+          <a href="<?=$this->recordLink()->getUrl($driver)?>" class="title <?=$this->record($driver)->getFormatClass($format)?>"><?
+            $summTitle = $driver->getTitle();
+            if (!empty($summTitle)) {
+                echo $this->escapeHtml($this->truncate($summTitle, 180));
+            } else {
+                echo $this->transEsc('Title not available');
+            }
+          ?></a>
+          <? $summAuthor = $driver->getPrimaryAuthor(); if (!empty($summAuthor)): ?>
+          <br />
+          <?=$this->transEsc('By')?>:
+          <a href="<?=$this->record($driver)->getLink('author', $summAuthor)?>">
+            <?=$this->escapeHtml($summAuthor)?>
+          </a>
+          <? endif; ?>
+          <? $summDate = $driver->getPublicationDates(); if (!empty($summDate)): ?>
+          <br/><?=$this->transEsc('Published')?>: (<?=$this->escapeHtml($summDate[0])?>)
+          <? endif; ?>
+       <?endif;?>
+      </li>
+    <? endforeach; ?>
+  </ul>
+<?endif;?>
diff --git a/themes/jquerymobile/templates/Recommend/RandomRecommend.phtml b/themes/jquerymobile/templates/Recommend/RandomRecommend.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..0df1e74df188b2630299fe4da6e7178c92ad5afc
--- /dev/null
+++ b/themes/jquerymobile/templates/Recommend/RandomRecommend.phtml
@@ -0,0 +1 @@
+<? /* Not supported in mobile theme. */ ?>
\ No newline at end of file