`
ghost138
  • 浏览: 45555 次
  • 性别: 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`...

    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.

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

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

    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