繁体   English   中英

在Lucene中嵌套搜索而不重复关键字

[英]Nesting searches in Lucene without duplicating keywords

我想使用以下逻辑在Lucene(实际上是Lucene.NET,但是我可以根据需要从Java转换)中进行搜索:

  1. 搜索字符串是:ABC
  2. 在索引中的一个字段中搜索与A,B或C匹配的任何内容。(查询: (field1:A field1:B field1:C)
  3. 对于在步骤2中不匹配的每个术语,在保留第二个字段的同时保留第一次搜索的结果(查询: (+(field1:A) +(field2:B field2:C))
  4. 对于第3步中不匹配的每个术语,请搜索第三个字段...
  5. 继续进行操作,直到用完所有字段,或者搜索已使用了每个术语。

目前,我的代码可以测试给定的搜索是否不产生结果,并将所有确实产生结果的结果与在一起。 但是我没有办法在针对每个字段进行测试之前停止它(这不必要地限制了结果)-当前它以如下查询结束: (+(field1:A field1:B field1:C) +(field3:A field3:B field3:C))当我希望它是(+(field1:A field1:C) +(field3:B)) 我不能只看第一次搜索的结果并从搜索字符串中删除单词,因为分析器在解析单词以进行搜索时会对其进行修饰,并且我无法解开它们以找出原始单词中的哪个它所对应的搜索词。

有什么建议么?


编辑:好的,通常我更喜欢抽象地描述我的问题,但是我认为其中的一部分会在过程中迷失,所以我会更具体。

我正在为一个需要具有多层搜索逻辑的站点构建搜索引擎。 我将跟踪的一些示例搜索为:

  1. 头戴式耳机
  2. 怪兽耳机
  3. 白色Monster耳机
  4. 白色Foobar耳机

索引包含具有七个字段的文档-与本示例相关的文档是:

  • “ datattype” :一个字符串,代表此文档代表什么类型的项目(产品,类别,品牌),因此我们知道如何显示它
  • “品牌” :相关的品牌(类别有多个品牌,产品和品牌各有一个)
  • “ path” :到给定类别的路径(例如,“ Audio> Headphones> In-Ear”的“ Audio Headphones In-Ear”)
  • “关键字” :描述产品的各种内容,在其他任何地方都没有。

通常,搜索的每个步骤的逻辑如下:

  1. 检查我们是否有匹配项。
  2. 如果是这样,则根据该匹配项过滤结果,并在下一步继续分析其余搜索词。
  3. 如果不是,请在下一步中解析搜索词。

每个步骤都类似于:

  • 搜索类别
  • 搜寻品牌
  • 搜索关键词

因此,这三个示例搜索应如何显示:

  1. 头戴式耳机
    • 搜索类别: +path:headphones +datatype:Category
    • 存在匹配项(“耳机”类别),并且原始查询中没有剩下任何单词,因此我们将其返回。
  2. 怪兽耳机
    • 搜索类别:`+(path:monster path:headphones)+ datatype:Category
    • 找到匹配的path:headphonesdatatype:Category ,使“ Monster”不匹配
    • 搜索品牌: +path:headphones +brand:monster
    • 找到了path:headphonesbrand:monster匹配项,原始查询中没有剩下任何单词,因此我们退回Monster的所有耳机​​。
  3. 白色Monster耳机
    • 搜索类别: +(path:monster path:headphones path:white) +datatype:Category
    • 找到了path:headphonesdatatype:Category匹配项,从而使“ White”和“ Monster”不匹配
    • 搜索品牌: +path:headphones +(brand:monster +brand:white)
    • 找到匹配的path:headphonesbrand:monster ,使“白色”无与伦比
    • 搜索关键字: +path:headphones +brand:monster +keywords:white
    • 有匹配项,并且没有原始查询中的任何单词,因此我们将其返回。
  4. 白色Foobar耳机
    • 搜索类别: +(path:foobar path:headphones path:white) +datatype:Category
    • 找到匹配的path:headphonesdatatype:Category ,使“ White”和“ Foobar”不匹配
    • 搜索品牌: +path:headphones +(brand:foobar +brand:white)
    • 找不到任何内容,因此我们继续。
    • 搜索关键字: +path:headphones +(keywords:white keywords:foobar)
    • 找到匹配项path:headphoneskeywords:white ,使“ Foobar”不匹配
    • ...(继续搜索其他字段,包括产品说明)...
    • 尚有不匹配的搜索字词(“ Foobar”),返回“未找到结果”

我有两个问题:

  1. 希望一旦所有内容都匹配就继续比赛(只有产品才有描述,所以一旦达到这一步,我们将永远不会返回不是产品的东西)。 我可以通过从此处使用denis的GetHitTerms来解决此问题 ,除了我然后最终在所有后续字段中搜索第一个匹配的术语,直到一切都匹配为止(例如,在示例2中,我将使用+path:headphones +(brand:headphones brand:monster) )。
  2. 尽管上面有我的示例,但我在path字段上的实际搜索查询看起来像+path:headphon +datatype:Taxonomy因为我正在处理它以进行搜索。 因此,我不能采用匹配的术语并将其从原始查询中删除(因为“ headphon”!=“ headphones”)。

希望这可以使我正在寻找的内容更加清楚。

我不了解您的用例,但您听起来好像在询问BooleanQuery API。 您可以通过调用getClauses来获取查询的子句。

一个简单的例子:

BooleanQuery bq = new BooleanQuery();
bq.add(new TermQuery(new Term("field1","a")), BooleanClause.Occur.SHOULD)
bq.add(new TermQuery(new Term("field1","b")), BooleanClause.Occur.SHOULD)

BooleanClause[] clauses = bq.getClauses();

编辑:也许您只是在要求搜索算法。 用伪代码:

generate_query (qs_that_matched, qs_that_didnt_match, level):
   new_query = qs_that_matched AND level:qs_that_didnt_match
   qs_still_unmatched = ...
   qs_which_just_matched = ...
   if qs_still_unmatched != null:
      return generate_query(qs_that_matched AND qs_which_just_matched, qs_still_unmatched, level+1)
   else:
      return qs_that_matched AND qs_which_just_matched

最后,我构建了一个QueryTree类,并将查询存储在树形结构中。 它存储对一个查询的函数的引用,要插入该查询的术语列表,是否应该对这些术语进行“与”或“或”运算,以及一个子项列表(代表匹配项的唯一组合)。

要执行下一级别的搜索,我只需在树中最深的节点上调用Evaluate(Func<string, QueryParser.Operator, Query> newQuery) ,并引用一个接受带有条件和运算符并返回正确查询的函数对于那套逻辑。 然后, Evaluate函数根据传递给它的不匹配项列表和所有祖先查询的结果集(通过与父项进行AND运算,与父项进行AND运算,依此类推)来测试该新查询。 然后,它使用GetHitTerms为每组匹配项创建子项,并将匹配的项提供给子项。 对每个搜索级别重复此步骤。


我怀疑有更好的方法可以做到这一点-我什至没有研究Xodarap提到的Bobo,而且我从没真正遇到过搜索工作(按照丹尼斯的说法)。 但是,它正在工作,这意味着该是该网站其他内容的时候了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM