【问题标题】:How to do better text search in neo4j如何在 neo4j 中进行更好的文本搜索
【发布时间】:2016-01-30 18:55:06
【问题描述】:

我有两种类型的节点 Article 和 TAG,其中 TAG 有两个属性 id 和 name。现在我想根据标签搜索所有文章。

(a : Article)-[:TAGGED]->(t : TAG) 

例如,如果我有“我爱我的国家”之类的标签,而我的查询字符串是“国家”,则使用以下查询成功搜索。

Match (a : Article)-[:TAGGED]->(t : TAG) 
where t.name =~ '*.country.*' 
return a;

但反之亦然,如果我的标签是“国家”并且我搜索“我爱我的国家”,那么它也应该显示与国家相关的文章。它还应该处理用户在两个单词之间输入多个空格的情况。在搜索时,我遇到了 lucene 和 solr,但我不知道如何使用它们。我使用 PHP 作为我的编码语言。

【问题讨论】:

    标签: solr neo4j lucene cypher


    【解决方案1】:

    [编辑]

    原答案

    这应该适合你:

    MATCH (a: Article)-[:TAGGED]->(t:TAG)
    WHERE ANY(word IN FILTER(x IN SPLIT({searchString}, " ") WHERE x <> '') 
      WHERE t.name CONTAINS word)
    RETURN a;
    

    {searchString} 是您的搜索字符串,用一个或空格分隔单词;例如:

    "i  love my    country"
    

    这个sn-p生成{searchString}中非空词的集合:

    FILTER(x IN SPLIT({searchString}, " ") WHERE x <> '')
    

    改进的答案

    此查询匹配单词(例如,如果查询字符串是“i love you”,则“i”将仅匹配标记中的单词“i”或“I”,而不仅仅是任何字母“i” )。它也不区分大小写。

    WITH REDUCE(res = [], w IN SPLIT({searchString}, " ") |
      CASE WHEN w <> '' THEN res + ("(?i).*\\b" + w + "\\b.*") ELSE res END) AS res
    MATCH (a: Article)-[:TAGGED]->(t:TAG)
    WHERE ANY (regexp IN res WHERE t.name =~ regexp)
    RETURN a;
    

    REDUCE 子句从{searchString} 生成一个单词集合,每个单词都被"(?i).*\b""\b.*" 包围,成为一个正则表达式,用于执行不区分大小写的搜索,带有单词边界。

    注意:正则表达式中的反斜杠 ("\") 实际上必须加倍,因为反斜杠是转义字符。

    【讨论】:

    • 不客气。还请记住upvote您接受的答案,除非您有理由不接受。
    • 如何使这个查询不区分大小写?
    • 我已经以其他方式完成了,我将 searchString 和 tagged 关键字都转换为小写并进行匹配。 MATCH (a: Article)-[:TAGGED]->(t:TAG) WHERE ANY(word IN FILTER(x IN SPLIT({searchString}, " ") WHERE x '') WHERE lower(t.name)包含较低(字))返回一个;它也是正确的方法还是在某些情况下可能会失败?
    • 您的方法(基于我的原始答案)不会只找到文字 - 但我不知道这对您是否重要。您的方法将用作不区分大小写的搜索,但它可能效率更低。
    • 感谢您指出使我支持不区分大小写的更改将使查询更加低效。我将遵循您更新的答案,但是当我执行您的查询时,它不会返回任何节点/行。例如我的标记词是“印度”,我的搜索字符串是“印度是我的国家”。
    【解决方案2】:

    Neo4j 在内部使用 Lucene 索引进行全文搜索。

    根据用户指南中的this page,使用不会对输入进行标记的 Lucene 关键字分析器,默认索引“类型”似乎是 exact

    这意味着,在不更改此索引设置的情况下,您只能运行与整个标签名称匹配的查询(在您的示例中,您正在运行与整个标签字符串匹配的通配符查询 '*.country.*') .

    我认为您实际上想要的是,根据您的要求,在插入图形数据时在空格中标记化 (type=fulltext),这样tag 字段实际上每个单词包含一个标记:1-i 2-love 3-my 4-country,其中任何一个都可以匹配查询词(不需要通配符:例如“country”或“I love my Chocolate”)

    【讨论】:

    • 但问题是我想要一个标签中的整个句子,因为我还必须向用户显示这些标签。
    • 索引设置应仅适用于“索引数据”(用于匹配的变体)被标记化的方式。这不应阻止 Neo4j 存储/返回原始标签字符串以供显示。
    猜你喜欢
    • 1970-01-01
    • 2020-10-29
    • 2014-03-16
    • 2022-08-18
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多