设为首页 收藏本站
查看: 858|回复: 0

[经验分享] act_as_solr

[复制链接]

尚未签到

发表于 2016-12-14 09:29:11 | 显示全部楼层 |阅读模式
  原文出处:http://www.quarkruby.com/2007/8/12/acts_as_solr-for-search-and-faceting
  Table of Contents



  • What is solr and acts_as_solr?
  • Getting Started
  • Basic usage
  • Pagination
  • Faceting
  • Boosting
  • Quick Tips
  • Testing Solr



For more acts_as_solr magic:
advanced acts_as_solr




  
Solr and acts_as_solr

  Solr is a search server based on lucene java search library with a HTTP/XML interface. Using Solr, large collections of documents can be indexed based on strongly typed field definitions, thereby taking advantage of Lucene's powerful full-text search features.  is a ruby on rails plugin adding Solr capabilities to activerecord models. It hides all configuration and manual setting efforts with Solr and provides you with simple find_by... methods. acts_as_solr can be used as a replacement to acts_as_ferret because of inbuilt full text search capabilities ;-) . The purpose of this article is to explain acts_as_solr with examples.
  acts_as_solr
  
Getting Started

  Installation: Installation is well explained on acts_as_solr homepage and getting started with acts_as_solr
  Note: acts_as_solr requires jre1.5 on system. Before running any of the solr methods make sure you start solr server with rake solr:start command.
  Our example model for this tutorial will be DigitalCamera [classname: Camera] with following fields


  • name (type:string)
  • brand (type:string) [we want faceted browsing on this field]
  • resolution (type:float) [we want faceted browsing on this field]
  • other fields which we do not want to index
  
Basic Usage : for search
Lets start with basic search and then we will move on to faceted browsing. You need to specify which of the columns from your model file you want to be indexed for search (if no :fields param is given, then all columns are indexed) :


1
2
3


class Camera
  acts_as_solr :fields=>[:name,:brand,:resolution]
end

Basic search can be done using:




@results = Camera.find_by_solr("canon powershot")

More options can be passed in a hash (2nd argument). Available Options are [:limit, :offset, :scores, :order, :operator]


  • limit: to limit the count of search results
  • offset: starting index of the search results.
  • scores: solr scores for each of the result returned
  • order: by which field results should be ordered and in asc/desc order?
  • operator: words in query should be separated by "and" or "or" i.e. all words should exist in matching results or any of the words respectively
  Note:



  • If you do not want Camera models objects as results, you can use find_id_by_solr which will return just id's from the Camera table (score option is not supported yet)
  • The result of find_by_solr is not an array of camera objects. Its a ActsAsSolr::SearchResults object.
  You can get model objects and count of results by


1
2


@products = @results.docs
@total_hits = @results.total_hits

Pagination
We will be using will_paginate for pagination (rails default pagination is buggy). One way of paginating returned results is explained nicely at Using will paginate with acts_as_solr. But we don't need an additional module for getting count of results returned. This module is an overhead because of extra Solr query. acts_as_solr returns the total number of results via find_by_solr and you don't need to call count_by_solr separately for getting result count. In your .rhtml file include this where you want pagination

1
2


<%= will_paginate WillPaginate::Collection.new((params[:page]||1),
                                                         (params[:products_per_page]||10),@total_hits) -%>

Faceting

  Presentation by Keith Instone is an excellent read on faceted browsing with examples.
  Back to acts_as_solr ... open the model file. Using option :facets => ... add the columns on which you want to allow faceted browsing.


1
2
3
4


class Camera
  acts_as_solr :fields=>[:name,:brand,:resolution],
               :facets=>[:brand,:resolution]
end

By default all fields are considered to be of type string. But resolution facet is of type float and we would like to have range queries on it (like find all cameras having resolution between 5 and 7). Modify the model to look like:

1
2
3
4


class Camera
  acts_as_solr :fields=>[:name,:brand,{:resolution=>:range_float}],
                :facets=>[:brand,:resolution]
end

When a user searches anything (lets say "powershot"), the values for other facets should get updated. Here is, how you can get updated facet values:

1
2


@results = Camera.find_by_solr("powershot",{:facets=>
                                            {:zeros=>false,:fields=>[:brand]}})

Here,


  • :zeros parameter tells solr not to return the brand values whose facet count is zero.
  • @results.facets["facet_fields"]["brand_facet"] contains the names of brand with the corresponding counts. A sample result:




    {"Canon USA"=>1, "Canon PowerShot"=>1, "Canon"=>91}

  But what about values for resolution facet as we have defined resolution to be varying float type (float_range)? Something like this does not work:


1
2
3


# INCORRECT
@results = Camera.find_by_solr("powershot",{:facets=>
                                            {:zeros=>false,:fields=>[:brand,:resolution]}})

We need to use facet_query param of find_by_solr with ranges for resolution predefined i.e. Solr cannot calculate the range for the float/int fields itself and we need to specify the range of values while querying solr. For example if values in resolution column range from 0 to 20 and we want to have 4 facet ranges. Your query would be something like

1
2
3
4
5
6
7


@results = Camera.find_by_solr("powershot",
                             {:facets=>{:zeros=>false,
                                        :fields=>[:brand],
                                        :query=>["resolution:[0 TO 4]","resolution:[5 TO 9]",
                                                    "resolution:[10 TO 14]","resolution:[15 TO 20]"]
                                              }
                              })

Resolution facet ranges can be obtained from output by @results.facets["facet_queries"]
If you want to display the results to the user as links along with counts (something like example images at the top), where user can make a further selection, you need to get results from solr using

1
2
3


@results = Camera.find_by_solr("powershot"+" AND resolution:[0 TO 4]",
                         {:facets=>{:zeros=>false, :fields=>[:brand]}})
## resolution queries has been removed since you already made a selection in resolution itself.

User wants multiple selections in resolution i.e. between 0 to 4 and between 6 to 7. So we can define query (first argument to find_by_solr) as "powershot" + " AND (resolution:[0 TO 4] OR resolution:[6 TO 7])".
But unfortunately, find_by_solr(query+" AND brand:Canon") doesn't seems to work
By default all fields are of type string and faceting for these fields is done using browse parameter i.e.

1
2
3
4
5
6


@results = Camera.find_by_solr(query,{:facets=>
                                  {:zeros=>false,
                                    :query=>["resolution:[0 TO 4]", "resolution:[5 TO 9]",
                                            "resolution:[10 TO 14]", "resolution:[15 TO 20]"],
                                    :browse=>["brand:Canon"]}
                                  })

and this is fine until you want to allow multiple selections for brand i.e. get products from canon and sony.
Note: I don't know how to make this work with browse field because multiple options in browse are separated by AND and :operator option from find_by_solr works only with words in query.
A good alternative is to redefine your model fields which are of string type to field_type as :facet. Our acts_as_solr declaration becomes:

1
2


acts_as_solr :fields=>[:name,{:brand=>:facet}, {:resolution=>:range_float}],
           :facets=>[:brand,:resolution]

This allow us to use brand in query itself like resolution making multiple options to be separated by OR as above. For ex. new query becomes: "powershot" + " AND (brand:Canon OR brand:Sony)"
Boosting
Using boost option you can give one field priority over the others. Just a small change in acts_as_solr declaration is enough.




acts_as_solr :fields => [{:name=>{:boost=>2}},:brand,:resolution]

Quick Tips



  • How to search solr with no query or 'nil' query. i.e. Product pages with navigation without a search query. Use query = "[* TO *]"

    1
    2
    3
    4
    5
    6
    7


    @results = Camera.find_by_solr("[* TO *]",
                                   {:facets=>{:zeros=>false,
                                         :fields=>[:brand],
                                         :query=>["resolution:[0 TO 4]", "resolution:[5 TO 9]",
                                                       "resolution:[10 TO 14]", "resolution:[15 TO 20]"]
                                                    }
                                  })

  • Already have database, how to integrate solr now? Goto ./script/console and run




    Camera.rebuild_solr_index

  • Adding or updating rows to table automatically adds/modifies them in table.
  • If you have already created index on solr (not acts_as_solr), it will not work with acts_as_solr. This is because, in solr configuration, schema.xml tells the solr exactly about the columns you are going to index, their data types. But, with acts_as_solr you never modify schema.xml. Actually, acts_as_solr uses dynamic fields to tell solr about the fields and their data types. So, acts_as_solr does not finds anything in your already created index because field names are no more same.
  
Testing Solr
Copy vendor/plugins/acts_as_solr/test/test_helper.rb modified as shown below.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25


class Test::Unit::TestCase
  begin
    Net::HTTP.get_response(URI.parse('http://localhost:8981/solr/'))
  rescue Errno::ECONNREFUSED
    raise "You forgot to 'rake solr:start RAILS_ENV=test', foo!"
  end

  def self.fixtures(*table_names)
    if block_given?
      Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
    else
      Fixtures.create_fixtures(Test::Unit:: TestCase.fixture_path, table_names)
    end
    table_names.each do |table_name|
      clear_from_solr(table_name)
      klass = instance_eval table_name.to_s.capitalize.singularize.camelize
      klass.find (:all).each{|content| content.solr_save}
    end
  end

  private
  def self.clear_from_solr(table_name)
    ActsAsSolr::Post.execute(Solr::Request::Delete.new(:query => "type_t:#{table_name.to_s.capitalize.singularize.camelize}")
  end
end

Modifications in the original file



  • removed top lines
  • added camelize for removing "_" from model names
  • added lines to test presence of test server running .. (from google groups)
  Now include, this file in your unit/functional tests just like you include test_helper.rb in all your test files. After you have saved above file as RAILS_APP/test/solr_test_helper.rb do not forget to include solr_test_helper in your test files and start writing your tests. :)
Oops! Still not working
Did you make sure that config/solr.yml has been configured for testing environment. (by default solr test server runs on port 8981)
References


  • acts_as_solr benchmark results
  • acts_as_solr performance on some live site
  • http://www.webdesignpractices.com/navigation/facets.html
  • http://cfis.savagexi.com/articles/2007/07/10/how-to-profile-your-rails-application
  • Deploying acts_as_solr on tomcat

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-314078-1-1.html 上篇帖子: 在Tomcat中使用solr 下篇帖子: solr搭建第一步
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表