如何使用 Gremlin 查询类似于搜索功能的 SQL?

12

我正在使用OrientDB类型图。 我需要Gremlin语法来搜索与SQL LIKE运算符相同的内容。

LIKE 'search%' or LIKE '%search%'

我已经使用 has 和 filter(在 http://gremlindocs.com/)进行了检查。然而,必须确定传递的确切值是使用 type 属性传递的。我认为这与搜索逻辑不符。

感谢任何帮助。

7个回答

12

11

尝试:

g.V().filter({ it.getProperty("foo").startsWith("search") })

或者

g.V().filter({ it.getProperty("foo").contains("search") })

1
.matches(".*search.*") - Minh Loc
有没有办法做“不喜欢”的操作? - Govind Prabhu
只需返回反转结果。g.V().filter({ !it.getProperty("foo").contains("search") }) - Daniel Kuppitz
你在使用哪个Gremlin服务器?Titan?Janus? - Luis Bosquez
首先,这个答案已经有5年的历史了,当时还不存在Janus。其次,我不认为我使用了任何服务器来测试这个查询。 - Daniel Kuppitz

6
您可以使用一些正则表达式来配合filter使用:
gremlin> g = TinkerGraphFactory.createTinkerGraph()
==>tinkergraph[vertices:6 edges:6]
gremlin> g.V.filter{it.name.matches(".*ark.*")}.name
==>marko

或者使用更多 Groovy 语法糖:
gremlin> g.V.filter{it.name==~/.*ark.*/}.name 
==>marko

上述答案(和被接受的答案)适用于TinkerPop 2.x,而以下内容适用于3.x,这是目前广泛使用的版本:
目前,TinkerPop 3.x不支持将正则表达式作为Gremlin核心语言的一部分,但是正则表达式可能可用于您正在使用的特定图形系统(DSE Graph、JanusGraph等),并且这些图形将提供自己的库以扩展带有正则表达式谓词(和/或其他搜索选项,如模糊和标记化)的Gremlin。请查阅您的图形文档以了解可用内容。
图形特定扩展将是执行基于正则表达式的搜索的最有效方法,因为它将依赖于内部索引函数,这些函数已经优化处理此类事情,但是也有通过闭包进行内存排序的正则表达式搜索方法,这与上面提到的TinkerPop 2.x答案类似。
gremlin> g = TinkerFactory.createModern().traversal()
==>graphtraversalsource[tinkergraph[vertices:6 edges:6], standard]
gremlin> g.V().filter{it.get().value('name').matches(".*ark.*")}
==>v[1]

由于我们正在使用闭包,因此可以在该函数中放置任何Java(在本例中为Groovy)代码。请注意,对于 it.get().value('name') 中的 it 是Groovy标记,它引用流中的当前 Traverser 并保存通过 get() 检索到的Vertex对象。

这种方法将在接受闭包的任何地方起作用,但并非所有图形都支持它们,因此并不是所有情况下都能使用。如果您不在JVM上(例如Python),则可能会向服务器提交Gremlin脚本或使用基于字节码的请求。如果您正在提交脚本,则应该能够像上面展示的那样提交请求。如果您使用字节码,则必须在遍历中显式声明lambda字符串,如Python中所示

最后,不建议使用闭包/lambda,因为它们会降低您代码的可移植性,暴露安全漏洞等问题。如果您需要正则表达式,则最好使用具有本机支持和包含特定于程序语言的自定义谓词的图形工具库。


1
请问我该如何在 Gremlin JavaScript 中使用正则表达式(匹配)? - Bằng
@CongBangDO - 你最终找到方法了吗? - L G
我已经更新了这个答案,适用于TinkerPop 3.x - 请注意,gremlin-javascript尚不支持基于字节码的遍历中的闭包/lambda。您将不得不发送一个脚本。这不是一个很好的解决方案,但这就是现状。 - stephen mallette
是的 - 这只是一些尚未完成的事情(但是图形提供程序之间的支持可能不稳定 - 并非所有支持Lambda的原因都与脚本相同):https://issues.apache.org/jira/browse/TINKERPOP-2001 - stephen mallette
很遗憾,我没有。 - Bằng
显示剩余3条评论

4
对于使用Gremlin Python(gremlin_python)的JanusGraph:
from gremlin_python.process.traversal import TextP
g.V().has('foo', TextP.containing('search'))

来源:https://docs.janusgraph.org/index-backend/text-search/

JanusGraph具有内置的全文本搜索功能,可以轻松地通过文本查询图形中的顶点和边。使用JanusGraph支持的任何索引后端(例如Elasticsearch),可以在不影响性能的情况下实现高效的全文搜索。可以使用Gremlin查询语言构建复杂的查询,并且可以方便地将全文搜索与其他JanusGraph查询组合使用。

4

如果有读者需要这个答案,这里提供一个更新的搜索方法(与已接受答案非常相似)

对于Gremlin控制台(gremlin.sh):


g.V().filter({ it.get().value("foo").contains("search") })

如果您的索引后端是ElasticSearch(可能也适用于其他索引后端),那么以下内容同样适用:

g.V().has("foo", Text.textContains("search"))

3
作为SimpleGraph项目的贡献者之一,我了解该项目中实现的解决方案。
示例: https://github.com/BITPlan/com.bitplan.simplegraph/blob/master/simplegraph-core/src/main/java/com/bitplan/gremlin/RegexPredicate.java
g().V().has("tosearch", RegexPredicate.regex("search.*"))

RegexPredicate

import java.util.function.BiPredicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.tinkerpop.gremlin.process.traversal.P;

// https://groups.google.com/forum/#!topic/gremlin-users/heWLwz9xBQc
// https://dev59.com/FWIk5IYBdhLWcg3wp_qM#45652897
public class RegexPredicate implements BiPredicate<Object, Object> {
    Pattern pattern = null;
    private Mode mode;

    enum Mode {
        FIND, MATCH
    }

    public RegexPredicate(String regex, Mode mode) {
        this.mode = mode;
        pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
    };

    public RegexPredicate(String regex) {
        this(regex,Mode.FIND);
    }

    @Override
    public boolean test(final Object first, final Object second) {
        String str = first.toString();
        Matcher matcher = pattern.matcher(str);
        switch (mode) {
        case FIND:
            return matcher.find();
        case MATCH:
            return matcher.matches();
        }
        return false;
    }

    /**
     * get a Regular expression predicate
     * 
     * @param regex
     * @return - the predicate
     */
    public static P<Object> regex(Object regex) {
        BiPredicate<Object, Object> b = new RegexPredicate(regex.toString());
        return new P<Object>(b, regex);
    }
}

0
我知道我晚了很多,但我也一直在尝试弄清楚这个问题,希望能够帮助到某些人。这是用Java实现的。TinkerPop版本为3.2.5。我不知道如何在不编写一些Java代码的情况下完成这个问题。
1)创建一个实现BiPredicate接口的枚举。(注意,此谓词允许通配符并且不区分大小写。)
public enum StringCompare implements BiPredicate<Object, Object> {
wildcard {
        @Override
        public boolean test(final Object first, final Object second) {

            String str = first.toString();
            String regex = second.toString();

            Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
            Matcher matcher = pattern.matcher(str);

            return matcher.matches();
        }
    }
}

2) 按照Java规则创建您的正则表达式。我发现这个链接非常有帮助。http://www.developer.com/java/data/using-java-regular-expressions.html

3) 使用has()方法,将其传递给属性键,并创建一个新的P对象。

String regex = "Mar.*"; //2
GraphTraversal<Vertex,Vertex> gtv = g.V().has("name", new P<>(StringCompare.wildcard, regex)); //3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接