Apache Solr Views and a terrible way to handle results per content type in Drupal 7

I’m betting on there being a better way to do this.  There just has to be.  But I haven’t figured it out, so here is how we’re using (abusing?) Views PHP and ApacheSolr Views  to deliver results on a per-content type basis.

apachesolr views with per content type results

apachesolr views with per content type results

To start with we create a new view

choose the correct solr index

choose the correct solr index

After the new view is created load a bunch of fields on in – it may be useful to remember that “Bundle” will return a content type by name, the “content” will return all of the fielded content in an string, and “entity_id” has the node value.  One cool thing you can do with the node id is then pass that as an argument to another view using Views Field View - be aware that this is somewhat performance naughty, but it’ll work if you want access to images in your results and don’t feel like creating a custom module to index images.

exclude fields from display

exclude fields from display

After getting your fields loaded I set their values to “Exclude from display” in the field settings

 

Our view with a few fields loaded

Our view with a few fields loaded

And of course don’t forget to add a Global: PHP field – here’s our view now

 

In the Global PHP comes this fubar stank piece of code

<?php
$type=$row->bundle; // Here we’ll get our content types
$content=$row->content; // This is all of the content per node that’s been indexed
$title=$row->label; // This is the node title
if ($type==”mobile_resource”)
{
$stop=”URL:”;
$startI = 1;
$stopI = strpos($content, $stop, $startI);
$text=substr($content, $startI, $stopI – $startI);
$trimtext=trim($text);
$startsAt = strpos($content, “URL:”) + strlen(“URL:”);
$endsAt = strpos($content, “Platform:”, $startsAt);
$result = substr($content, $startsAt, $endsAt – $startsAt);
$trimurl=trim($result, chr(0xC2).chr(0xA0)); // This will save someone time – be sure to trim the nbsp spaces from your content when needed

echo “<a href=”$trimurl”>$title: $trimtext</a>”; // and then print stuff as you see fit

}
else if ($type == “cme_class”) // and more of the same
{
$stop=”Description:”;
$startI = 1;
$stopI = strpos($content, $stop, $startI);
$text=substr($content, $startI, $stopI – $startI);
$trimtext=trim($text);
$url=$row->path_alias;
echo “<a href=”$url”>$trimtext</a>”;

$startsAt = strpos($content, “Location:”) + strlen(“Location:”);
$endsAt = strpos($content, “Date and Time:”, $startsAt);
$location = substr($content, $startsAt, $endsAt – $startsAt);

$startsAt2 = strpos($content, “Time:”) + strlen(“Time:”);
$endsAt2 = strpos($content, “Registration”, $startsAt2);
$time = substr($content, $startsAt2, $endsAt2 – $startsAt2);

print(“<h5>Time: $time</h5>”);
print(“<h5>Place: $location</h5>”);
}
else if ($type == “employee_bio”) //etc
{
$startsAt = 1;
$endsAt = strpos($content, “My Education”, $startsAt);
$who = substr($content, $startsAt, $endsAt – $startsAt);
$url=$row->path_alias;
echo “<a href=”$url”>$who</a>”;
}
else
{
$url=$row->path_alias;
echo “<a href=”$url”>$title</a>”;
}
?>

And really… I’m pretty embarrassed by this.   It’s raunchy and rank.  It works.  The facets facet and so on… I just can’t believe that this is the way to do things.  I’ve looked at Solr Panels and feel like there must be a way to do better – maybe having multiple views pre-faceted by bundle at the view level and the made in to content panes?   Anyone with some sense of how to improve this is encouraged to chime in…. Bueller?  Bueller….

This entry was posted in Planet_Drupal and tagged , , , , , . Bookmark the permalink.

11 Responses to Apache Solr Views and a terrible way to handle results per content type in Drupal 7

  1. Bob Newby says:

    I believe the following starter toolkit is preferable to what you are using:

    - SearchAPI
    - SearchAPI Solr
    - FacetAPI
    - Views
    - Page Manager
    - Panels

    In particular, the SearchAPI architecture is solid, generalized, and agnostic vis-a-vis the search engine being used. SearchAPI Solr and FacetAPI play extremely well with it.

    Given the terrain you have already covered with Apache Solr and FacetAPI, learning the ins and outs of SearchAPI and SearchAPI Solr should be relatively straightforward.

    Good luck,

    Bob

    • alibama says:

      how does search api vary with regards to handling displays per content type? or is this something done with panels. I’ve looked at the search api and don’t see where it differs? Thanks for the comment though – am more than glad to check it out.

      • Bob Newby says:

        I am unclear what you are trying to accomplish with respect to “displays per content type”. Can you let me know?

        In any case, SearchAPI etc. are not responsible for displaying results. That is the work, of course, of some combination of: each content type’s display manager (perhaps augmented by Display Suite and/or Panelizer displays); Views; and Panels (including Mini Panels).

        For what it is worth, my site’s search is architected as follows:

        1. Each content type has a DS (Display Suite) view mode called “Search result”. Each “Search result” display contains a single field, which is a content-type specific embedded view of type-specific data for a single node.

        2. Each of these embedded single-node views employs time-based caching, for example 6 hours for the result cache and the display/rendering cache. Each single-node view can of course contain whatever data you want and lay it out however you want with whatever display plugin you want.

        3. The search view returns multiple rows, each of which boils down to the search-indexed node that matches the search view’s exposed and unexposed filters; the most common exposed filter is a match-all-keywords (or a match the exact phrase) text filter.

        4. Each of the search view’s rows displays the respective node’s Full Content, rendered by that node’s “Search result” view mode. Thus each rendered row is cached, whereas you absolutely do not want to cache the search view itself.

        5. The search view is based on the specific SearchAPI Solr index you want to employ. That index is connected to a Solr server. The index specifies the fields to index, one of which can be each node’s fully rendered HTML content; you will also normally index the title plus any important taxonomy terms, etc.

        6. The search index is further configured, via its Workflow tab, to index only selected content types, to ignore a set of “stop words”, and so on.

        7. The search index also configures the desired search facets, based on Facet API of course.

        8. FacetAPI supplies a block for each configured facet. These blocks augment the search view’s exposed filter(s). I use Page Manager/Panels to host the search view’s results in the main region of the page. Another region of the page holds both the search view’s exposed filter(s) and its configured facets. (These can be presented in another page region as tabs.)

        9. If you are also supporting SearchAPI Saved Searches, then the Saved Search blocks can be added to the filters-and-facets region of the page, or to another page region.

        10. You can of course utilize content-type-specific search views, each of which is based on your master SearchAPI Solr index. In this case, a search view uses a non-exposed filter that narrows its content types to one or several of the indexed types.

        I think that’s the full picture…

        Bob

        • alibama says:

          I think you nailed it – I’m going to test this out and do another writeup called “Bob’s way doesn’t suck at all!”

  2. bruno says:

    Hey,

    You could overwrite the view template and use a preprocess hook to alter the variables passed to the template.

    You could also use a module like “display suite”. With this module, you can manage your displays for each content type. I always prefer working with “node displays” instead of “fields” inside views. You get the advantage that the node is rendered so all node features are also added (example: you get contextual links). But because you are working with solr. I guess when you use this approach, only the id of the node will be used from solr and the node display will be rendered with a database query.

    • alibama says:

      Hi Bruno,
      my feeling is that if I have to overwrite the view template and write a preprocess hook I’m not that much better off. I think you’re spot on with the display suite option as we’re already using that in our node displays… am going to test that + the Search API Bob recommended to see whether those will play nice together. Thanks!

  3. Robin says:

    Perhaps https://drupal.org/project/eva (Entity Views Attachment) would be useful too.

    • alibama says:

      eva rocks – i think if we go down the display suite path (and it’s looking like we will) that may play a role

  4. Kevin says:

    We simply did not use Views. It was a hell of a lot easier to talk to Solr and get what we need.

    http://www.prugallo.com

    Real Estate and Rentals are simple Form API forms that submit and call SearchAPI solr functions directly and process the response from Solr.

    In addition, I wrote a custom module to store the View Mode render of the entity in Solr as a document so Drupal does not have to load and process entity ID results.

    https://drupal.org/project/search_api_solr_view_modes