MetaSearch
MetaSearch is extensible searching for your form_for enjoyment. It “wraps” one of your ActiveRecord models, providing methods that allow you to build up search conditions against that model, and has a few extra form helpers to simplify sorting and supplying multiple parameters to your condition methods as well.
NOTE
The successor to MetaSearch is Ransack. It’s got features that MetaSearch doesn’t, along with some API changes. I haven’t had the time to dedicate to making it bulletproof yet, so I’m releasing a 1.1.x branch of MetaSearch to help with migrations to Rails 3.1.
This is intended to be a stopgap measure.
t’s important to note that the long-term migration path for your apps should be toward Ransack, which is written in a more sane manner that will make supporting new versions of Rails much easier going forward.
Getting Started
In your Gemfile:
gem "meta_search" # Last officially released gem # gem "meta_search", :git => "git://github.com/ernie/meta_search.git" # Track git repo
or, to install as a plugin:
rails plugin install git://github.com/ernie/meta_search.git
In your controller:
def index @search = Article.search(params[:search]) @articles = @search.all # load all matching records # @articles = @search.relation # Retrieve the relation, to lazy-load in view # @articles = @search.paginate(:page => params[:page]) # Who doesn't love will_paginate? end
In your view:
<%= form_for @search, :url => articles_path, :html => {:method => :get} do |f| %> <%= f.label :title_contains %> <%= f.text_field :title_contains %><br /> <%= f.label :comments_created_at_greater_than, 'With comments after' %> <%= f.datetime_select :comments_created_at_greater_than, :include_blank => true %><br /> <!-- etc... --> <%= f.submit %> <% end %>
Options for the search method are documented at MetaSearch::Searches::ActiveRecord.
“Wheres”, and what they’re good for
Wheres are how MetaSearch does its magic. Wheres have a name (and possible aliases) which are appended to your model and association attributes. When you instantiate a MetaSearch::Builder against a model (manually or by calling your model’s search method) the builder responds to methods named for your model’s attributes and associations, suffixed by the name of the Where.
These are the default Wheres, broken down by the types of ActiveRecord columns they can search against:
All data types
-
equals (alias: eq) - Just as it sounds.
-
does_not_equal (aliases: ne, noteq) - The opposite of equals, oddly enough.
-
in - Takes an array, matches on equality with any of the items in the array.
-
not_in (aliases: ni, notin) - Like above, but negated.
-
is_null - The column has an SQL NULL value.
-
is_not_null - The column contains anything but NULL.
Strings
-
contains (aliases: like, matches) - Substring match.
-
does_not_contain (aliases: nlike, nmatches) - Negative substring match.
-
starts_with (alias: sw) - Match strings beginning with the entered term.
-
does_not_start_with (alias: dnsw) - The opposite of above.
-
ends_with (alias: ew) - Match strings ending with the entered term.
-
does_not_end_with (alias: dnew) - Negative of above.
Numbers, dates, and times
-
greater_than (alias: gt) - Greater than.
-
greater_than_or_equal_to (aliases: gte, gteq) - Greater than or equal to.
-
less_than (alias: lt) - Less than.
-
less_than_or_equal_to (aliases: lte, lteq) - Less than or equal to.
Booleans
-
is_true - Is true. Useful for a checkbox like “only show admin users”.
-
is_false - The complement of is_true.
Non-boolean data types
-
is_present - As with is_true, useful with a checkbox. Not NULL or the empty string.
-
is_blank - Returns records with a value of NULL or the empty string in the column.
So, given a model like this…
class Article < ActiveRecord::Base belongs_to :author has_many :comments has_many :moderations, :through => :comments end
…you might end up with attributes like title_contains, comments_title_starts_with, moderations_value_less_than, author_name_equals, and so on.
Additionally, all of the above predicate types also have an _any and _all version, which expects an array of the corresponding parameter type, and requires any or all of the parameters to be a match, respectively. So:
Article.search :author_name_starts_with_any => ['Jim', 'Bob', 'Fred']
will match articles authored by Jimmy, Bobby, or Freddy, but not Winifred.
Advanced usage
Narrowing the scope of a search
While the most common use case is to simply call Model.search(params[:search]), there may be times where you want to scope your search more tightly. For instance, only allowing users to search their own projects (assuming a current_user method returning the current user):
@search = current_user.projects.search(params[:search])
Or, you can build up any relation you like and call the search method on that object:
@projects_with_awesome_users_search = Project.joins(:user).where(:users => {:awesome => true}).search(params[:search])
ORed conditions
If you’d like to match on one of several possible columns, you can do this:
<%= f.text_field :title_or_description_contains %> <%= f.text_field :title_or_author_name_starts_with %>
Caveats:
-
Only one match type is supported. You can’t do title_matches_or_description_starts_with for instance.
-
If you’re matching across associations, remember that the associated table will be INNER JOINed, therefore limiting results to those that at least have a corresponding record in the associated table.
Compound conditions (any/all)
All Where types automatically get an “any” and “all” variant. This has the same name and aliases as the original, but is suffixed with _any and _all, for an “OR” or “AND” search, respectively. So, if you want to provide the user with 5 different search boxes to enter possible article titles:
<%= f.multiparameter_field :title_contains_any, *5.times.inject([]) {|a, b| a << {:field_type => :text_field}} + [:size => 10] %>
Multi-level associations
MetaSearch will allow you to traverse your associations in one form, generating the necessary joins along the way. If you have the following models…
class Company < ActiveRecord::Base has_many :developers end class Developer < ActiveRecord::Base belongs_to :company has_many :notes end
…you can do this in your form to search your companies by developers with certain notes:
<%= f.text_field :developers_notes_note_contains %>
You can travel forward and back through the associations, so this would also work (though be entirely pointless in this case):
<%= f.text_field :developers_notes_developer_company_name_contains %>
However, to prevent abuse, this is limited to associations of a total “depth” of 5 levels. This means that while starting from a Company model, as above, you could do Company -> :developers -> :notes -> :developer -> :company, which has gotten you right back where you started, but “travels” through 5 models total.
In the case of polymorphic belongs_to associations, things work a bit differently. Let’s say you have the following models:
class Article < ActiveRecord::Base has_many :comments, :as => :commentable end class Post < ActiveRecord::Base has_many :comments, :as => :commentable end class Comment < ActiveRecord::Base belongs_to :commentable, :polymorphic => true validates_presence_of :body end
Your first instinct might be to set up a text field for :commentable_body_contains, but you can’t do this. MetaSearch would have no way to know which class lies on the other side of the polymorphic association, so it wouldn’t be able to join the correct tables.
Instead, you’ll follow a convention Searchlogic users are already familiar with, using the name of the polymorphic association, then the underscored class name (AwesomeClass becomes awesome_class), then the delimiter “type”, to tell MetaSearch anything that follows is an attribute name. For example:
<%= f.text_field :commentable_article_type_body_contains %>
If you’d like to match on multiple types of polymorphic associations, you can join them with _or_, just like any other conditions:
<%= f.text_field :commentable_article_type_body_or_commentable_post_type_body_contains %>
It’s not pretty, but it works. Alternately, consider creating a custom search method as described below to save yourself some typing if you’re creating a lot of these types of search fields.
Adding a new Where
If none of the built-in search criteria work for you, you can add new Wheres. To do so, create an initializer (/config/initializers/meta_search.rb, for instance) and add lines like:
MetaSearch::Where.add :between, :btw, :predicate => :in, :types => [:integer, :float, :decimal, :date, :datetime, :timestamp, :time], :formatter => Proc.new {|param| Range.new(param.first, param.last)}, :validator => Proc.new {|param| param.is_a?(Array) && !(param[0].blank? || param[1].blank?) }
See MetaSearch::Where for info on the supported options.
Accessing custom search methods (and named scopes!)
MetaSearch can be given access to any class method on your model to extend its search capabilities. The only rule is that the method must return an ActiveRecord::Relation so that MetaSearch can continue to extend the search with other attributes. Conveniently, scopes (formerly “named scopes”) do this already.
Consider the following model:
class Company < ActiveRecord::Base has_many :slackers, :class_name => "Developer", :conditions => {:slacker => true} scope :backwards_name, lambda {|name| where(:name => name.reverse)} scope :with_slackers_by_name_and_salary_range, lambda {|name, low, high| joins(:slackers).where(:developers => {:name => name, :salary => low..high}) } end
To allow MetaSearch access to a model method, including a named scope, just use search_methods in the model:
search_methods :backwards_name
This will allow you to add a text field named :backwards_name to your search form, and it will behave as you might expect.
In the case of the second scope, we have multiple parameters to pass in, of different types. We can pass the following to search_methods:
search_methods :with_slackers_by_name_and_salary_range, :splat_param => true, :type => [:string, :integer, :integer]
MetaSearch needs us to tell it that we don’t want to keep the array supplied to it as-is, but “splat” it when passing it to the model method. Regarding :types: In this case, ActiveRecord would have been smart enough to handle the typecasting for us, but I wanted to demonstrate how we can tell MetaSearch that a given parameter is of a specific database “column type.” This is just a hint MetaSearch uses in the same way it does when casting “Where” params based on the DB column being searched. It’s also important so that things like dates get handled properly by FormBuilder.
multiparameter_field
The example Where above adds support for a “between” search, which requires an array with two parameters. These can be passed using Rails multiparameter attributes. To make life easier, MetaSearch adds a helper for this:
<%= f.multiparameter_field :moderations_value_between, {:field_type => :text_field}, {:field_type => :text_field}, :size => 5 %>
multiparameter_field works pretty much like the other FormBuilder helpers, but it lets you sandwich a list of fields, each in hash format, between the attribute and the usual options hash. See MetaSearch::Helpers::FormBuilder for more info.
checks and collection_checks
If you need to get an array into your where, and you don’t care about parameter order, you might choose to use a select or collection_select with multiple selection enabled, but everyone hates multiple selection boxes. MetaSearch adds a couple of additional helpers, checks and collection_checks to handle multiple selections in a more visually appealing manner. They can be called with or without a block. Without a block, you get an array of MetaSearch::Check objects to do with as you please.
With a block, each check is yielded to your template, like so:
<h4>How many heads?</h4> <ul> <% f.checks :number_of_heads_in, [['One', 1], ['Two', 2], ['Three', 3]], :class => 'checkboxy' do |check| %> <li> <%= check.box %> <%= check.label %> </li> <% end %> </ul>
Again, full documentation is in MetaSearch::Helpers::FormBuilder.
Sorting columns
If you’d like to sort by a specific column in your results (the attributes of the base model) or an association column then supply the meta_sort parameter in your form. The parameter takes the form column.direction where column is the column name or underscore-separated association_column combination, and direction is one of “asc” or “desc” for ascending or descending, respectively.
Normally, you won’t supply this parameter yourself, but instead will use the helper method sort_link in your views, like so:
<%= sort_link @search, :title %>
Or, if in the context of a form_for against a MetaSearch::Builder:
<%= f.sort_link :title %>
The @search object is the instance of MetaSearch::Builder you got back earlier from your controller. The other required parameter is the attribute name itself. Optionally, you can provide a string as a 3rd parameter to override the default link name, and then additional hashed for the options and html_options hashes for link_to.
By default, the link that is created will sort by the given column in ascending order when first clicked. If you’d like to reverse this (so the first click sorts the results in descending order), you can pass +:default_order => :desc+ in the options hash, like so:
<%= sort_link @search, :ratings, "Highest Rated", :default_order => :desc %>
You can sort by more than one column as well, by creating a link like:
<%= sort_link :name_and_salary %>
If you’d like to do a custom sort, you can do so by setting up two scopes in your model:
scope :sort_by_custom_name_asc, order('custom_name ASC') scope :sort_by_custom_name_desc, order('custom_name DESC')
You can then do sort_link @search, :custom_name and it will work as you expect.
All sort_link-generated links will have the CSS class sort_link, as well as a directional class (ascending or descending) if the link is for a currently sorted column, for your styling enjoyment.
This feature should hopefully help out those of you migrating from Searchlogic, and a thanks goes out to Ben Johnson for the HTML entities used for the up and down arrows, which provide a nice default look.
Including/excluding attributes and associations
If you’d like to allow only certain associations or attributes to be searched, you can do so inside your models
class Article < ActiveRecord::Base attr_searchable :some_public_data, :some_more_searchable_stuff assoc_searchable :search_this_association_why_dontcha end
If you’d rather blacklist attributes and associations rather than whitelist, use the attr_unsearchable and assoc_unsearchable method instead. If a whitelist is supplied, it takes precedence.
Excluded attributes on a model will be honored across associations, so if an Article has_many :comments and the Comment model looks something like this:
class Comment < ActiveRecord::Base validates_presence_of :user_id, :body attr_unsearchable :user_id end
Then your call to Article.search will allow :comments_body_contains but not :comments_user_id_equals to be passed.
Conditional access to searches
search_methods, attr_searchable, attr_unsearchable, assoc_searchable, and assoc_unsearchable all accept an :if option. If present, it should specify a Proc (or other object responding to call) that accepts a single parameter. This parameter will be the instance of the MetaSearch::Builder that gets created by a call to Model.search. Any unused search options (the second hash param) that get passed to Model.search will be available via the Builder object’s options reader, and can be used for access control via this proc/object.
Example:
assoc_unsearchable :notes, :if => proc {|s| s.options[:access] == 'blocked' || !s.options[:access]}
Localization
MetaSearch supports i18n localization in a few different ways. Consider this abbreviated example “flanders” locale:
flanders: activerecord: attributes: company: name: "Company name-diddly" developer: name: "Developer name-diddly" salary: "Developer salary-doodly" meta_search: or: 'or-diddly' predicates: contains: "%{attribute} contains-diddly" equals: "%{attribute} equals-diddly" attributes: company: reverse_name: "Company reverse name-diddly" developer: name_contains: "Developer name-diddly contains-aroonie"
First, MetaSearch will use a key found under meta_search.attributes.model_name.attribute_name, if it exists. As a fallback, it will use a localization based on the predicate type, along with the usual ActiveRecord attribute localization (the activerecord.attributes.model_name keys above). Additionally, a localized “or” can be specified for multi-column searches.
Contributions
There are several ways you can help MetaSearch continue to improve.
-
Use MetaSearch in your real-world projects and submit bug reports or feature suggestions.
-
Better yet, if you’re so inclined, fix the issue yourself and submit a patch! Or you can fork the project on GitHub and send me a pull request (please include tests!)
-
If you like MetaSearch, spread the word. More users == more eyes on code == more bugs getting found == more bugs getting fixed (hopefully!)
-
Lastly, if MetaSearch has saved you hours of development time on your latest Rails gig, and you’re feeling magnanimous, please consider making a donation to the project. I have spent hours of my personal time coding and supporting MetaSearch, and your donation would go a great way toward justifying that time spent to my loving wife. :)
相关推荐
metasearch.dll
元搜索引擎(MetaSearch)的特点是把多个独立搜索引擎的搜索结果整合、控制、优化,再把搜索结果输出到客户端。元搜索引擎不需要庞大的网页数据库,而能够搜索到更加丰富、准确的内容。K-MetaSearch是由Kwindsoft...
asp metasearch K-MetaSearch Engine
元搜索引擎(MetaSearch)的特点是把多个独立搜索引擎的搜索结果整合、控制、优化,再把搜索结果输出到客户端。元搜索引擎不需要庞大的网页数据库,而能够搜索到更加丰富、准确的内容。K-MetaSearch是由Kwindsoft...
元搜索引擎(MetaSearch)的特点是把多个独立搜索引擎的搜索结果整合、控制、优化,再把搜索结果输出到客户端。元搜索引擎不需要庞大的网页数据库,而能够搜索到更加丰富、准确的内容。K-MetaSearch是由Kwindsoft自主...
【标题】"源代码-K风元搜索引擎系统 K-MetaSearch v3.1 SP3.zip" 涉及的是一个基于ASP技术开发的搜索引擎系统。K-MetaSearch v3.1 SP3是一个专为网站提供站内搜索功能的软件,它能够帮助用户快速、有效地在大量网页...
在ASP源码中,K风元搜索引擎系统 K-MetaSearch v3.1 SP3是一个基于ASP技术构建的搜索引擎解决方案,它旨在帮助网站实现对内部信息的高效检索和管理。 这个系统的核心功能可能包括: 1. **搜索引擎接口**:K-...
MetaSearch 的可扩展性极强,这得益于它的插件架构。 在MetaSearch的插件架构中,每个搜索引擎或数据源都可以被视为一个独立的插件。开发者可以根据需要编写新的插件来支持不同的搜索引擎,如百度、谷歌、必应等,...
ASP实例开发源码—K风元搜索引擎系统asp版 K-MetaSearch v3.1 SP3.zip ASP实例开发源码—K风元搜索引擎系统asp版 K-MetaSearch v3.1 SP3.zip ASP实例开发源码—K风元搜索引擎系统asp版 K-MetaSearch v3.1 SP3.zip
这可能涉及TF-IDF(词频-逆文档频率)或其他文本分析算法,以及倒排索引的建立,以加速关键词匹配。 4. **查询处理**:系统需要解析用户的搜索请求,执行查询,并返回最相关的新闻标题。这可能涉及查询优化,如布尔...
K-MetaSearch v3.1 SP3作为基于ASP的应用,展现了其在搜索引擎领域的应用可能性,提供了一个集成多引擎搜索的解决方案。随着技术的演进,虽然ASP已被ASP.NET取代,但在维护旧项目或特定场景下,ASP仍然有着不可替代...
标题提到的"metasearch"项目是一个受到Searx影响的Metasearch引擎,其核心是用Node.js编程语言实现的。Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它以其非阻塞I/O模型和事件驱动的特性,特别适合用于...
常见的网站seo术语文档: 搜索结果(search result):作为对搜索者的搜索请求的响应,搜索引擎返回匹配网页的链接, 这个链接就是搜索结果。搜索引擎使用多种技术来断定哪个网页与哪个搜索请求匹配,并且 根据相关...
【标题】:“hw2-metaSearch:作业2” 这个标题表明我们正在探讨一个关于“元搜索”的项目,可能是某个在线课程或编程挑战的第二部分。元搜索引擎并不直接抓取网页,而是通过集成多个搜索引擎的结果来提供更全面的...
"maltego-metasearch"是一个专门针对Searx实例的Maltego本地变换,它允许用户在Maltego环境中直接查询并获取Searx搜索引擎的搜索结果。 Searx是一个开源的元搜索引擎,它聚合了多个不同的搜索引擎,并提供隐私保护...
$ cd metasearch-public 在app / config-sample.json文件中为特定插件添加API令牌(和Redis参数): { " hybrid_analysis " : { " api " : " XXXXXXXXXXXXXXXXXX " , " secret " : " XXXXXXXXXXXXXXXXXX " }, ...
- MRDD是多排名文档多样化的缩写,用于解决搜索引擎返回结果过于相似的问题。在这个项目中,MRDD被用来对不同搜索引擎的搜索结果进行排名和多样性处理,确保返回给用户的结果既相关又具有多样性。 3. **查询聚类**...
ASP源码,压缩包解压密码:www.cqlsoft.com
元搜索 功能齐全的 Node.js 元搜索引擎 特征 使用 3 个流行的搜索引擎(Google、Bing、Blekko) 使用组合乘法非零和倒数秩融合算法的 2 种结果聚合类型 使用 K-Means 机器学习算法对 3 种不同集群大小进行聚类 ...
爬虫(Web Crawler)是一种自动化程序,用于从互联网上收集信息。其主要功能是访问网页、提取数据并存储,以便后续分析或展示。爬虫通常由搜索引擎、数据挖掘工具、监测系统等应用于网络数据抓取的场景。...