如何加快neo4j中多值属性的查找速度



我在neo4j中创建了以下节点(其中100万个(:

CREATE (p:Person { name: 'user1', email: ['user1@gmail.com', 'user1@yahoo.com'] }) RETURN p
CREATE (p:Person { name: 'user2', email: ['user2@gmail.com', 'user2@yahoo.com'] }) RETURN p
...
CREATE (p:Person { name: 'user1000000', email: ['user1000000@gmail.com', 'user1000000@yahoo.com'] }) RETURN p

我创建了以下索引:

CREATE BTREE INDEX i1 FOR (n:Person) ON (n.name)
CREATE BTREE INDEX i2 FOR (n:Person) ON (n.email)

有了上面的数据,下面的查询需要2ms才能完成,我可以在桌面上每秒同时执行大约2800个这样的查询。

MATCH (p:Person) WHERE p.name = 'user10' RETURN DISTINCT p.name

但是下面的查询需要710ms才能完成,我在桌面上每秒只能同时执行大约5个这样的查询。

MATCH (p:Person) WHERE 'user10@gmail.com' IN p.email RETURN DISTINCT p.name

有什么方法可以加快第二次查询的速度并提高吞吐量吗?

编辑1

正如@jose_bacoy在他的回答中所建议的那样,我尝试使用单独的节点来发送电子邮件。

我创建了以下节点:

CREATE (m1:mail { email: 'user1@gmail.com' })
CREATE (m2:mail { email: 'user1@yahoo.com' })
CREATE (p:Person { name: 'user1' })
CREATE (p) - [:attribute] -> (m1)
CREATE (p) - [:attribute] -> (m2)
RETURN p
...
CREATE (m1:mail { email: 'user1000000@gmail.com' })
CREATE (m2:mail { email: 'user1000000@yahoo.com' })
CREATE (p:Person { name: 'user1000000' })
CREATE (p) - [:attribute] -> (m1)
CREATE (p) - [:attribute] -> (m2)
RETURN p

并将它们索引如下:

CREATE BTREE INDEX i1 FOR (n:Person) ON (n.name)
CREATE BTREE INDEX i2 FOR (n:mail) ON (n.email)

速度也不错。延迟:4ms,每秒处理1850个查询。这样做的问题是,下面的查询执行得非常糟糕。

MATCH (p:Person) - [:attribute] -> (m1:mail)
MATCH (p) - [:attribute] -> (m2:mail)
WHERE m1.email = 'user10@gmail.com' OR m2.email = 'user10@yahoo.com'
RETURN DISTINCT p.name

在我的桌面上,延迟约为5秒,吞吐量不到每秒1次。

编辑2:

我按照Charchit Kapoor下面的建议修改了查询。以下是我使用的查询。

MATCH (p:Person) - [:attribute] -> (m:mail)
WHERE m.email IN ['user10@gmail.com', 'user10@yahoo.com']
RETURN DISTINCT p.name

具有大约4ms的延迟和大约每秒2600个查询的吞吐量。

您的数据模型与查询不一致。电子邮件是"个人"节点中的电子邮件列表,您正在列表中进行搜索。下面是一个脚本,用于将您的数据模型从Person.email更改为Person-[:HAS_email]->电子邮件APOC函数迭代将把Person节点分为多个批,并将并行运行以提高效率。确保已安装APOC。

然后它将创建(Person(->(电子邮件(关系,并在完成后亲自移除财产。您可以根据自己的口味更改批量大小(每批10k(。您还想为电子邮件创建一个唯一的索引。我将由你决定如何做。

CALL apoc.periodic.iterate(
"MATCH (p:Person) RETURN p as person;", 
"WITH person
UNWIND person.email as email
MERGE (e:Email {email: email})
MERGE (person)-[:HAS_EMAIL]->(e)
SET person.email = null;", 
{batchSize:10000, parallel:true, retries:3});

完成此操作并在Email.Email上创建索引后,分析显示正在使用BTREE索引:

PROFILE MATCH (p:Person) -[:HAS_EMAIL] -> (e:Email)
WHERE e.email = 'user10@gmail.com'
RETURN DISTINCT p.name
BTREE INDEX e:Email(email) WHERE
email = $autostring_0

以前,它在$autostring_0 IN p.email上显示NodeLabelByScan和Filter。即使在列表上创建索引,也不会使用它。

您的第二个查询可以采用不同的结构,首先查找所有相关的电子邮件,然后查找相关的用户:

MATCH (m1:mail)
WHERE m1.email IN ['user10@gmail.com', 'user10@yahoo.com']
MATCH (p)-[:attribute]->(m1)
RETURN DISTINCT p.name

最新更新