Здесь происходит несколько вещей, которые должны повлиять на ваше решение о моделировании.
Во-первых, когда мы извлекаем значение поля из узла, мы нормализуем данные. Вместо того, чтобы одинаковые значения (например, «Великобритания») дублировались для всех: узлов лиц, которые живут в Великобритании, теперь у нас есть только один узел: Страна с кодом «Великобритании», и все узлы людей, которые там живут, имеют : Отношения LIVES_IN к узлу страны. Так что в этом аспекте мы избегаем дублирования строковых данных в базе данных.
Еще одна вещь, которую следует учитывать, заключается в том, что в Neo4j поиск и фильтрация свойств часто являются одними из более дорогих операций, поэтому часто вы можете оптимизировать их, настраивая запросы и моделируя, чтобы минимизировать поиск свойств и фильтрацию свойств.
В первом случае нам всегда нужно отфильтровать всех моих друзей, чтобы получить друзей из желаемой страны. Хотя это не будет проблемой для такого небольшого набора данных, друзья одного человека, когда дело доходит до более сложных запросов, вы можете выполнять хороший поиск и фильтрацию свойств, что может замедлить выполнение запроса.
Во втором случае планировщик может быть в состоянии оптимизировать, сопоставляя страну с поиском по индексу (on: Country (code)) в дополнение к поиску узла Стефана (и если планировщик не делает этого мы можем использовать подсказки планировщика, чтобы заставить его). Предварительно сопоставив узел страны в Великобритании, мы можем расширить шаблон для друзей и узла их страны, который будет выполнять операцию ExpandInto в узле Великобритании (или хеш-соединение узла, в зависимости от подхода планировщика). В любом случае операция фильтрации вообще не требует доступа к свойству, вместо этого она выполняет фильтрацию на основе нашего предварительно согласованного британского узла (который скрывает фильтры на основе идентификатора графа узла), что является эффективной операцией.
Вы можете использовать PROFILE или EXPLAIN, чтобы проверить, как планировщик выполнит запрос.
Другим аспектом, который напрямую не связан с производительностью, является гибкость и полезность, которые вы разблокируете, извлекая подобные объекты вместо того, чтобы сохранять их как поля свойств.
Извлекая страны в их собственные узлы, мы теперь можем использовать эти узлы в разных контекстах. В то время как в настоящее время у нас есть отношения: LIVED_IN между узлами: Person и: Country, теперь мы можем добавлять любые другие виды отношений к узлам Country и от них. Мы могли бы иметь такие данные на графике:
(:Person)-[:TRAVELED_TO]->(:Country)
(:Language)-[:COMMONLY_SPOKEN_IN]->(:Country)
(:State)-[:LOCATED_IN]->(:Country)
и более. Несмотря на то, что мы можем использовать эти шаблоны самостоятельно, реальная сила приходит, когда нам нужно включить несколько частей в один шаблон, что позволяет нам иметь богатый контекст при запросе.
Например: «Я хочу знать, какие мои друзья живут или путешествовали в страну, где обычно говорят по-испански, и вернуть друга и страны, которые совпадают»
MATCH (me:Person {name:'InverseFalcon'})-[:FRIENDS_WITH]->(friend)-[:LIVES_IN | TRAVELED_TO]->(country:Country)<-[:COMMONLY_SPOKEN_IN]-(:Language {name:'Spanish'})
RETURN friend, collect(country.code) as countries
Путем рефакторинга нашей модели, подобной этой, мы избегаем грубого извлечения значений свойств и необходимости использовать их в последующих сопоставлениях (аналогично объединениям таблиц).