`
ghost138
  • 浏览: 45758 次
  • 性别: Icon_minigender_1
  • 来自: ...重庆
最近访客 更多访客>>
社区版块
存档分类
最新评论

全文检索之Ferret

    博客分类:
  • ROR
阅读更多

什么是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”)

那么:

  1. 在我们的rails应用中创建了一个 /index/development/member 文件夹,索引文件将会保留在这里。
  2. 所有Member model的查询都会被保存,并且对first_name 和 last_name进行索引。每当对Member进行 add/update/delete 操作时,索引就会自动更新。如果你需要重新生成一个索引,只需要删除对应的文件夹,重启服务,这样在下次进行表查询时将会重新建立索引。
  3. acts_as_ferret会调用ferret的 Search_Each 方法处理索引
  4. 我们得到一些返回数据

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进行了下面的操作:

  1. 调用find_id_by_contents,得到id集合
  2. 跟踪所有返回的id,得到实际的model
  3. 返回一个貌似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

分享到:
评论
1 楼 ghost138 2011-04-11  
貌似在我的系统里面用不起来噢~郁闷的东西

相关推荐

    Ruby搜索引擎Ferret.zip

    Ferret 是 Java 全文搜索引擎 Lucene 的 Ruby 移植版本。 标签:Ferret

    Go-Ferret一种声明式Web爬虫系统

    Go-Ferret是一种基于Go语言开发的声明式Web爬虫系统,它的主要目的是为了简化从互联网上抓取和处理数据的过程。在Web爬虫领域,Go-Ferret提供了一种高效且易于使用的解决方案,尤其适合于UI测试、机器学习以及数据...

    ferret 6.84 for win7 64

    FERRET 绘图软件 6.84 for win64 安装方式,解压到任意目录,直接执行bin\bash.exe或bin\mintty.exe原方式操作,直接执行bin\ferret_v6.84.exe 直接进入FERRET

    ferret简明手册

    ### FERRET简明手册知识点概述 #### 一、FERRET简介与基本操作 - **Commandline模式**:启动FERRET时,默认进入命令行模式,提示符为“yes?”,用户可以通过此模式输入命令。 - **FERRET-GUI**:通过`ferret-gui`...

    E022-渗透测试常用工具-使用ferret进行Cookie劫持.pdf

    在这个过程中,使用了ferret工具来执行Cookie劫持,这是一种常见的攻击手段,用于获取用户的登录凭据,特别是那些存储在Cookie中的会话ID。以下是整个过程的详细解释: 1. **环境准备**: 在这个场景中,我们有两...

    Ferret工具源代码

    几年前的黑帽子大会后传出的一个工具Ferret。作者声称可以利用他截获邮箱登录过程中的cookie信息。进而可以随意侵入他人的信箱。曾在黑帽子大会上当场演示如何破解gmail,hotmail等信箱。终于等到作者把代码和工具都...

    工具Ferret(含代码)

    工具Ferret是一款在黑帽子大会上亮相的安全工具,主要用于研究目的,其功能是截获邮箱登录过程中的Cookie信息。在网络安全领域,理解这样的工具是非常重要的,因为它揭示了网络攻击者可能使用的手段,同时也为安全...

    Ferret ruby下的搜索引擎技术

    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 是用于实时嵌入式控制系统的免费软件 lisp 实现_Makefile_代码_相关文件_下载

    Ferret 是一个免费软件 lisp 实现,旨在用于实时嵌入式控制系统。Ferret lisp 编译成自包含的C++11。生成的代码可在支持C++11兼容编译器的任何操作系统和/或微控制器之间移植。它已经过验证,可以在从内存低至2KB 的...

    Ferret-crx插件

    这款插件的独特之处在于它提供了一个统一的、便捷的搜索入口,允许用户在多功能框中输入特定的指令来启动搜索,极大地简化了网络搜索的过程。 在浏览器的地址栏或多功能框中,用户只需输入“#”(井号)加任何想要...

    Image Ferret-开源

    这款软件的独特之处在于它能够自动学习用户的偏好,根据用户对图像的喜好进行智能推荐,极大地提升了图片搜索的个性化体验。 在开源软件的世界中,"Image Ferret"扮演着一个创新的角色,它允许开发者和用户深入到...

    Arduino-ferret.zip

    Arduino-ferret.zip,ferret是一个用于实时嵌入式控制系统的自由软件lisp实现。,Arduino是一家开源软硬件公司和制造商社区。Arduino始于21世纪初,深受电子制造商的欢迎,Arduino通过开源系统提供了很多灵活性。

    基于Rails的菲普斯网站管理系统 v0.8.5.rar

    软件介绍 Fepss(菲普斯)第一个推出在线为企业提供不限用户...本网站系统是作为OA系统的前端展示系统,所倚赖的包都在plugin目录,其中还提供了一个基于ferret的全文检索功能,需要通过 gem install ferret 方式安装。

    Ferret CMS-开源

    Ferret CMS 的核心亮点之一是其内置的工作流机制。工作流是内容管理中的关键组成部分,它允许对内容的生命周期进行精确控制。在 Ferret CMS 中,工作流能够定义一系列的任务、状态和规则,这些任务可以按顺序分配给...

    Ferret.Net-开源

    【标题】"Ferret.Net-开源" 【描述】中的知识点: 1. **Ferret.Net**:这是一个专为IT专业人士设计的开源类库,它主要用于处理网络套接字通信,提供跨平台的支持。 2. **基于接口**:这意味着Ferret.Net的设计遵循...

    Python库 | txtferret-0.1.0-py3-none-any.whl

    "ferret"这个词在英语中指的是雪貂,一种善于挖掘和寻找的小动物。在这里,它可能是象征着库能够深入文本数据中,挖掘出有价值的信息。版本号"0.1.0"表明这是该库的初步版本,可能存在更多的更新和发展空间。 ...

    Ferret4J-开源

    Ferret4J旨在成为Java应用程序的轻量级MVC框架。 它基于以模型为中心的体系结构,并努力减少干扰。 您可以在我的博客中找到更多信息,网址为http://blackship.eu/category/my-projects/jferret/

    pnw-ferret:政治与战争的数据收集和分析工具

    "pnw-ferret"是一个专门用于政治与战争数据收集和分析的工具,它以其高效的数据处理能力和深度洞察力在IT行业中占据了一席之地。这个工具以“雪貂”为代号,暗示了其在信息搜索和挖掘中的敏捷性和精准性。主要由...

    ferret-opencv

    雪貂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...

Global site tag (gtag.js) - Google Analytics