如何使用Sphinx的BuildExcerpts

1 投票
1 回答
1609 浏览
提问于 2025-04-17 12:32

我设置了一个Sphinx的配置文件。我的数据结构非常简单,只有两个字段,一个是标题(title),另一个是正文(body)。标题是小说的名字,正文就是整本小说。为了简单起见,我只添加了一本小说。索引器工作得很好,使用Python的API查询Sphinx也非常简单。我对目前的进展感到很满意,这似乎是我调查过的最容易设置的全文搜索引擎(比Lucene或Solr简单得多,而且比Woosh快)。

我没有使用任何数据库后端。我把我的小说保存在普通的.txt文件中,并通过这个简单的xml(通过xmlpipe)添加了一个示例。

<?xml version="1.0" encoding="utf-8"?>
<sphinx:docset>
       <sphinx:document id="1">
             <title><![CDATA[Dan Simmons - I Canti di Hyperion 3 - Endymion]]></title>
             <body><![CDATA[ * ALL THE NOVEL HERE * ]]></body>
       </sphinx:document>
</sphinx:docset>

顺便说一下,我在档案中搜索了“tartaruga”,这是意大利语的“乌龟”,我确定这个词在文件中。实际上,它出现了三次,我想这就是Sphinx返回给我的结果('hits': 3)。这是完整的结果:

{'attrs': [],
'error': '',
'fields': ['title', 'body'],
'matches': [{'attrs': {}, 'id': 1, 'weight': 1}],
'status': 0,
'time': '0.392',
'total': 1,
'total_found': 1,
'warning': '',
'words': [{'docs': 1, 'hits': 3, 'word': 'tartaruga'}]}

我最终想要的结果是这样的:

[
  {
    'title': 'Dan Simmons - I Canti di Hyperion 3 - Endymion',
    'body': 'il vecchio mostrò quel suo sorriso a becco di tartaruga. — non bisogna dimenticare il palazzo dello shrike, né il nostro vecchio amico shrike, giusto? non ce ne sono altre?'
  },
  {
    'title': 'Dan Simmons - I Canti di Hyperion 3 - Endymion',
    'body': '— vieni più vicino, raul endymion. — la voce pareva il rumore di una lama spuntata che sfregasse su pergamena. le labbra si muovevano come il becco d\'una tartaruga.'
  },
  {
    'title': 'Dan Simmons - I Canti di Hyperion 3 - Endymion',
    'body': 'il becco di tartaruga ebbe una contrazione, la grossa testa si mosse in un cenno d\'assenso. notai ora che il viso del vecchio, malgrado i danni provocati dai secoli, aveva ancora tratti netti e spigolosi... un\'aria da satiro.'
  },
]

我的意思是,想要一个包含出现次数的数组,里面有摘录来自哪本书,以及这个词在上下文中的位置(我选择了句子,但在匹配前后可以有n个词也可以)。我想我需要使用BuildExcerpts,但该怎么做呢?

另外,如果我想同时匹配“tartaruga”(乌龟)和“tartarughe”(乌龟的复数),我想发出一个像tartarug*这样的查询。在Sphinx中该怎么做呢?谢谢!

1 个回答

0

我在做一个项目的时候也遇到过类似的情况。我建议,如果你只打算处理一本书,那把整本书作为一个字段加载并不是个好主意;如果你要处理很多书,那就更不合适了。以下是我处理的方式。

  1. 把书的内容分成一页一页存储在MySQL数据库里。
  2. 用Sphinx这个工具在数据库中搜索几百万页的文本——速度非常快,可以返回你想找的每一页(或者根据数据库中的页数,只返回前30页或其他数量)。
  3. 使用摘录生成器从某一页提取内容,并高亮显示搜索的关键词。
  4. 如果Python无法使用摘录生成器(可能只有PHP可以用),你也可以用正则表达式来完成同样的工作——只需要找到你的搜索词,然后用正则表达式提取前后的一些文本,再用另一个正则表达式来添加高亮效果。

你可以写一个Python脚本(我用的是从bash命令行运行的PHP脚本)来逐页提取文本,清理内容,然后把它添加到数据库中。

你需要一个至少有两个表的数据库,类似于:

books (字段可以叫 id, name, author)

pages (字段可以是 id, book_id, page_text)

Sphinx会返回一个页面的ID,然后你可以用简单的查询从MySQL中获取这页内容……

SELECT page_text FROM pages WHERE id = $idreturnedbysphinx;

然后把返回的文本发送给文本摘录器/高亮器。

Sphinx可以搜索精确的单词或词根(还有很多其他功能),但你需要在sphinx.conf文件中进行设置。

你至少需要两个索引定义:

indexer indexname1
{
     #source database connection and sql query
      source                = src1
      path                  = /var/data/indexname1
     [... other settings ...]
     #make sure stemming is switched off
     morphology             = none


}
#child index inherits the above, and add stemming
index indexname1stemmed : indexname1
{
    path            = /var/data/indexname1stemmed
    morphology      = stem_en
    index_exact_words   = 1
}

然后你还需要在Sphinx搜索中指定你想使用的匹配模式。我不太清楚Python的语法,但Sphinx的手册写得比我更清楚:

http://sphinxsearch.com/docs/current.html#matching-modes

你可以不使用SQL数据库,而是把内容保存在文本文件中,但我建议每页一个文本文件,这样更容易管理,否则你又会回到把整本电子书作为搜索结果的情况。

撰写回答