什么是Ferret
Ferret,是用ruby开发的基于Apache Lucene的全文检索引擎库, 安装Ferret:
gem install ferret
在ferret的代码中,只有少量的ruby代码,大部分是c代码。这里有Ferret API,并在其中提供了一份教程Ferret Tutorial。
Acts_As_Ferret
Ferret是ruby库,在rails中如果想使用,就要用到Jens Kramer 的Acts As Ferret了,它提供了简单的接口,我们可以快速的创建复杂的搜索索引。
在你的rails中,以插件的形式安装acts_as_ferret
ruby script/plugin install svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret
基本用法
下面我们从一个简单的用法开始。
首先需要在你的model中添加需要被索引 的项目
class Member < ActiveRecord::Base
acts_as_ferret :fields => [:first_name, :last_name]
end
在这里我们是将特定的名字进行索引,搜索的时候将返回这些索引的符合结果。
做一个简单的搜索实例
Acts as Ferret为你的ActiveRecord model增加了搜索方法, 和其他的教程不同,我们使用find_id_by_contents:
当我们调用
total_results, members = Member.find_id_by_contents(”Gregg”)
那么:
- 在我们的rails应用中创建了一个 /index/development/member 文件夹,索引文件将会保留在这里。
- 所有Member model的查询都会被保存,并且对first_name 和 last_name进行索引。每当对Member进行 add/update/delete 操作时,索引就会自动更新。如果你需要重新生成一个索引,只需要删除对应的文件夹,重启服务,这样在下次进行表查询时将会重新建立索引。
- acts_as_ferret会调用ferret的 Search_Each 方法处理索引
- 我们得到一些返回数据
members = [
{:model => “Member”, :id => “4″, :score => “1.0″},
{:model => “Member”, :id => “21″, :score => “0.93211″},
{:model => “Member”, :id => “27″, :score => “0.32212″}
]
我们得到了前10条记录(当然我只显示了3条),包括了每条记录的id和搜索得分(search scores)。
但是,当返回记录有40条的时候,我们仍将得到10条记录。
如何得到多于10条记录呢?
find_id_ by_contents可以传递一些参数进去:
- offset:默认是0。The offset of the start of the section of the result-set to return(译者:我脑海中的说法和英文的不一样,就是返回结果所需要的偏移量,默认是从0记录开始,返回10条记录,但是如果offset为10,那 就是从第10条开始,返回10条记录。用中文这么一句话我说不好。呵呵)。这个用于对返回结果进行分页。
- limit:默认是10。返回你想要得到的结果数。也是在分页中被使用。
在find_id_by_contents使用代码块
results = []
total_results = Member.find_id_by_contents(”Gregg”) {|result|
results.push result
}
在这,你可能并不想只得到结果的id,那么可以在这里做一个转换,得到返回的model集合。
results = []
total_results = Member.find_id_by_contents(”Gregg”) {|result|
results.push Member.find(result[:id])
}
当然,这有更好的办法
使用find_by_contents
@results = Member.find_by_contents(”Gregg”)
find_by_contents进行了下面的操作:
- 调用find_id_by_contents,得到id集合
- 跟踪所有返回的id,得到实际的model
- 返回一个貌似ActiveRecord的集合,其实它是一个ActsAsFerret::SearchResults类,下面是它的一些额外特性
注意哦
members = Member.find_by_contents(”Gregg”)
# It gives us total hits!
puts “Total hits = #{members.total_hits}”
for member in members
puts “#{member.first_name} #{member.last_name}”
# And the search Score!
puts “Search Score = #{member.ferret_score}”
end
注意里面的total_hits和ferret_score,在数据库中他们并不存在的哦。
进行分页
注:下面代码中使用了Roman Mackovcak’s blog的例子。
在model中添加下面这个方法
def self.full_text_search(q, options = {})
return nil if q.nil? or q==”"
default_options = {:limit => 10, :page => 1}
options = default_options.merge options
# get the offset based on what page we’re on
options[:offset] = options[:limit] * (options.delete(:page).to_i-1)
# now do the query with our options
results = Member.find_by_contents(q, options)
return [results.total_hits, results]
end
在你的application.rb中添加
def pages_for(size, options = {})
default_options = {:per_page => 10}
options = default_options.merge options
pages = Paginator.new self, size, options[:per_page], (params[:page]||1)
return pages
end
在controller中添加
def search
@query = params[:query]
@total, @members = Member.full_text_search(@query, :page => (params[:page]||1))
@pages = pages_for(@total)
end
在页面中
<%= link_to ‘Previous page’, { :page => @pages.current.previous, :query => @query} if @pages.current.previous %>
<%= pagination_links(@pages, :params => { :query=> @query }) %>
<%= link_to ‘Next page’, { :page => @pages.current.next, :query => @query} if @pages.current.next %>
上面的代码可以完成大部分工作了,但是acts_as_ferret还有其他的优秀特性的。
其他形式的查询字串
- “Gregg Pollack”将在所有字段中搜索”Gregg”和”Pollack”
- “Gregg OR Pollack”将搜索”Gregg”或”Pollack”
- “Gregg~”模糊搜索,返回搜索包含”Gregg”字样的结果
- “first_name:Gregg”,搜索first_name是”Gregg”的记录,排除其他索引。
- “+first_name:Gregg -last_name:Jones”,布尔查询,查询所有first_name是”Gregg”并且last_name不是”Jones”的记录
更多复杂查询,可以参考 Apache Lucene Parser Syntax。
添加非model和非字段(Adding Non-Model or Non-Standard Fields)
现在对我们例子做一个修改,我们有许多书,每本书有一些作者,如果你不仅要索引书的标题,还要索引书的作者,该怎么办呢?
我们需要操作的是两个表,可是我们不能去对两个不同的索引进行查找。这时需要修改我们的model
/model/book.rb
class Book < ActiveRecord::Base
acts_as_ferret :fields => [:title, :author_name]
def author_name
return “#{self.author.first_name} #{self.author.last_name}”
end
end
这样在搜索书的标题时,书的作者也能被搜索到。
你可以对任何model方法的返回值进行索引,甚至可以重新格式化你的字段(fields)。
比如你在使用 acts_as_taggable ,对你的model进行tag标注,并且希望在搜索的时候你的tag一并被搜索到。那么:
class Book < ActiveRecord::Base
acts_as_taggable
acts_as_ferret :fields => [:title, :tags_with_spaces]
def tags_with_spaces
return self.tag_names.join(” “)
end
end
原文:If you were using the acts_as_taggable plugin you might not even need the extra function, and use “:tag_list” in the ferret field list, as shown onJohnny’s Thoughts. I’m not nearly as cool though, I’m using the acts_as_taggable gem.
译文:如果你在以插件形式使用acts_as_taggable,那么就会出现Johnny’s Thoughts中提到的问题,(具体情况大家去看那个博客吧,这个地方留意一下)。这时你需要在ferret索引字段列表使用”:tag_list”。译者:因为作者也在用插件形式使用ferret。插件冲突的事情由此也需要注意了。
排序
到目前为止,我们得到的记录都是排好序列的搜索结果。那么如果我们想得到按照我们想根据的字段进行排列的结果,比如书的标题,该如何做呢?
原文:The first thing you need to do is make sure the field you are trying to sort by is untokenized. Unfortunately, by making a field untokenized I’m not indexing it to be searchable anymore. This makes for a little funky coding.
作者:”if something is untokenized it will not be searchable ”
译者:首先你需要确定,需要排序的字段没有被索引过。所以我们要对上面的代码做一点修改。
acts_as_ferret :fields => {
:title => {},
:tags_with_spaces => {},
:title_for_sort => {:index => :untokenized}
}
def title_for_sort
return self.title
end
记得,如果你想重新建立索引,只需要删除对应的文件夹,并重启服务。
译者:重建索引也可以实用Model.rebuild_index这个方法。
s = Ferret::Search::SortField.new(:title_for_sort, :reverse => false)
@total, @members = Book.full_text_search(@query,
{:page => (params[:page]||1), :sort => s})
这样我就得到了按照书的title的排序。
如果你想按照日期排序,那就需要把日期转换成integer类型,具体的请参考this Slash Dot Dash
字段储存
在进入下一节(相当重要的一节)之前,我们需要研究下如何储存已被索引的数据(data)。
如果你现在看一下你的索引文件(indexes),你会发现那里并没有你的数据。默认情况下,acts_as_ferret在这种可复写的情况下并不储存你的数据(in a recoverable form),仅是索引它。
“那么,如果我的数据很小,我想在我的索引中储存它,该怎么办呢?”
这是个好问题,如果你的数据很小,而且你只是关注一个字段的信息,你可以加速你的索引。
acts_as_ferret :fields => {
:title => {:store => :yes},
:author_name => {:store => :yes}
}
当我们进行查询时,我们需要对这个特殊的字段进行说明(”lazy load”)
@books = Book.find_by_contents(”Jason”, :lazy => [:title, :author_name])
这样我们在渲染页面时,并没有调用数据库。
< % @books.each do |book| %>
%lt;li> “< %= book.title %>” by
< %= book.author_name %>%lt;/li%gt;
< % end %>
高亮显示搜索词
下面是用ferret实现搜索词的高亮显示。
不过这有个前提,就是需要对你的搜索词进行储存(must have your search fields stored),上面已经介绍了。
所以需要对上面的代码做一点点修改了:
< % @books.each do |book| %>
<li>
“< %= book.highlight(”Jason”, :field => :title, :num_excerpts => 1, :pre_tag => ““, :post_tag => ““) %>” by
< %= book.highlight(”Jason”, :field => :author_name, :num_excerpts => 1, :pre_tag => ““, :post_tag => ““) %>
</li>
< % end %>
你的搜索结果会是:
1. “Story of Gregg” by Jason Seifer
2. “Jason’s Book” by Gregg Pollack
3. “Gregg certainly is the Man” by Jason Seifer
高亮显示功能还有其他的方法,比如,如果你搜索的字段内容很长,例如博客文章,那么将会返回一个片断,搜索词被高亮显示。更多参考 Highlight in the API
使用Boost(设定搜索优先级)
最后介绍一下Boost属性。Boost属性可以提升索引的优先顺序。
acts_as_ferret :fields => {
:title => {:boost => 2},
:author => {:boost => 0}
}
这段代码表明,title搜索结果要优先于author结果的显示。但是这并不是说,所有的title记录在author记录前显示。如果一条author记录完全匹配搜索词,那么它会优先显示。
Perhaps this feature should be called “Nudge” instead of “Boost”. I thought I could use a large boost to get all the title results to appear above the author results. I was mistaken, one can only “Nudge” the scores, but never separate them, as I was hoping.
译者:大家看一下那个连接的文章,这段英文的意思是,使用boost是提升部分优先级,而别指望它能把title和author分开。
产品环境应用
因为很多人是在产品环境下使用,所以一致的想法认为,你需要运行一个DRB Server
相关推荐
Ferret 是 Java 全文搜索引擎 Lucene 的 Ruby 移植版本。 标签:Ferret
Go-Ferret是一种基于Go语言开发的声明式Web爬虫系统,它的主要目的是为了简化从互联网上抓取和处理数据的过程。在Web爬虫领域,Go-Ferret提供了一种高效且易于使用的解决方案,尤其适合于UI测试、机器学习以及数据...
FERRET 绘图软件 6.84 for win64 安装方式,解压到任意目录,直接执行bin\bash.exe或bin\mintty.exe原方式操作,直接执行bin\ferret_v6.84.exe 直接进入FERRET
### FERRET简明手册知识点概述 #### 一、FERRET简介与基本操作 - **Commandline模式**:启动FERRET时,默认进入命令行模式,提示符为“yes?”,用户可以通过此模式输入命令。 - **FERRET-GUI**:通过`ferret-gui`...
在这个过程中,使用了ferret工具来执行Cookie劫持,这是一种常见的攻击手段,用于获取用户的登录凭据,特别是那些存储在Cookie中的会话ID。以下是整个过程的详细解释: 1. **环境准备**: 在这个场景中,我们有两...
几年前的黑帽子大会后传出的一个工具Ferret。作者声称可以利用他截获邮箱登录过程中的cookie信息。进而可以随意侵入他人的信箱。曾在黑帽子大会上当场演示如何破解gmail,hotmail等信箱。终于等到作者把代码和工具都...
工具Ferret是一款在黑帽子大会上亮相的安全工具,主要用于研究目的,其功能是截获邮箱登录过程中的Cookie信息。在网络安全领域,理解这样的工具是非常重要的,因为它揭示了网络攻击者可能使用的手段,同时也为安全...
ruby下的搜索引擎。With the introduction of Ferret, Ruby users now have one of the fastest and most flexible search libraries available. And it's surprisingly easy to use.
对于互联网用户来说,提升信息检索效率是提升生产力的重要途径之一。Ferret-crx插件正是抓住了这一需求点,通过技术手段来解决实际问题,展现了浏览器扩展程序在提升用户网络体验方面的巨大潜力。在未来,我们有理由...
Ferret 是一个免费软件 lisp 实现,旨在用于实时嵌入式控制系统。Ferret lisp 编译成自包含的C++11。生成的代码可在支持C++11兼容编译器的任何操作系统和/或微控制器之间移植。它已经过验证,可以在从内存低至2KB 的...
这款软件的独特之处在于它能够自动学习用户的偏好,根据用户对图像的喜好进行智能推荐,极大地提升了图片搜索的个性化体验。 在开源软件的世界中,"Image Ferret"扮演着一个创新的角色,它允许开发者和用户深入到...
Arduino-ferret.zip,ferret是一个用于实时嵌入式控制系统的自由软件lisp实现。,Arduino是一家开源软硬件公司和制造商社区。Arduino始于21世纪初,深受电子制造商的欢迎,Arduino通过开源系统提供了很多灵活性。
软件介绍 Fepss(菲普斯)第一个推出在线为企业提供不限用户...本网站系统是作为OA系统的前端展示系统,所倚赖的包都在plugin目录,其中还提供了一个基于ferret的全文检索功能,需要通过 gem install ferret 方式安装。
Ferret CMS 的核心亮点之一是其内置的工作流机制。工作流是内容管理中的关键组成部分,它允许对内容的生命周期进行精确控制。在 Ferret CMS 中,工作流能够定义一系列的任务、状态和规则,这些任务可以按顺序分配给...
【标题】"Ferret.Net-开源" 【描述】中的知识点: 1. **Ferret.Net**:这是一个专为IT专业人士设计的开源类库,它主要用于处理网络套接字通信,提供跨平台的支持。 2. **基于接口**:这意味着Ferret.Net的设计遵循...
"ferret"这个词在英语中指的是雪貂,一种善于挖掘和寻找的小动物。在这里,它可能是象征着库能够深入文本数据中,挖掘出有价值的信息。版本号"0.1.0"表明这是该库的初步版本,可能存在更多的更新和发展空间。 ...
Ferret4J旨在成为Java应用程序的轻量级MVC框架。 它基于以模型为中心的体系结构,并努力减少干扰。 您可以在我的博客中找到更多信息,网址为http://blackship.eu/category/my-projects/jferret/
"pnw-ferret"是一个专门用于政治与战争数据收集和分析的工具,它以其高效的数据处理能力和深度洞察力在IT行业中占据了一席之地。这个工具以“雪貂”为代号,暗示了其在信息搜索和挖掘中的敏捷性和精准性。主要由...
雪貂opencv 用于OpenCV雪貂绑定(require '[ferret-opencv.core :as cv])(def cam (cv/video-capture 0))(let [f (cv/query-capture cam)] (cv/imwrite "image_latest.png" f))样品CMake cmake_minimum_required...