Фильтрация вычисленных значений с помощью Elasticsearch

#node.js #elasticsearch #graphql

#node.js #elasticsearch #graphql

Вопрос:

Итак, у нас есть схема людей и схема проекта, обе из которых используются на отдельных страницах, где вы можете фильтровать результаты. Мы находимся на этапе, когда понимаем, что нам нужно фильтровать что-то вроде текущих проектов, но в списке ПОЛЬЗОВАТЕЛЕЙ. Однако данные для этого хранятся в проектах, и у нас возникают проблемы с поиском чистого способа перекрестных ссылок на схемы и фильтрации по вычисленному значению.

Например. Фильтровать список людей по проектам, которые в данный момент активны (т.е. текущее время).

Похоже, что в ES нет никакого способа сделать это — мой текущий вариант — объединить их во внешнем интерфейсе и выполнить там еще один «фильтр», но это кажется хакерским.

Отображение данных в списке пользователей не проблема, это фильтрация.

Кто-нибудь сталкивался с такой ситуацией раньше и как вы ее разрешали? Ценю любую информацию. Спасибо!

Ответ №1:

Если я правильно понимаю, у вас есть два отдельных индекса для людей и проектов.

К сожалению, единственный способ сделать все правильно — это денормализовать ваши данные в Elasticsearch и включить проекты в список пользователей.

Комментарии:

1. Да, я так и думал, но мой ведущий считает, что это плохая идея. Ну что ж, я пытался. Спасибо!

2. Я имею в виду, что в зависимости от вашего размера вы, вероятно, могли бы решить это на уровне вашего приложения, но это ненадежно и будет медленным по сравнению с денормализованными данными. 🙂

Ответ №2:

Вы также можете использовать отношения родитель-потомок.

Пожалуйста, прочтите эти отличные сообщения в блоге: https://rockset.com/blog/can-i-do-sql-style-joins-in-elasticsearch / а затем родительско-дочернее моделирование в Elasticsearch https://blog.mimacom.com/parent-child-elasticsearch / По предыдущей ссылке показаны примеры в ElasticSearch 5.6 и 6. Я приведу примеры, которые работают в ES 7:

Согласно сообщению:

Существует четыре распространенных подхода к управлению данными в Elasticsearch:

Денормализация, объединения на стороне приложения, вложенные объекты, отношения родитель-потомок

  • Взаимно однозначные отношения: сопоставление объектов
  • Отношения «один ко многим»: вложенные документы и модель «родитель-потомок»
  • Отношения «многие ко многим»: денормализация и объединения на стороне приложения

Проблемы с родительско-дочерними отношениями

Запросы являются более дорогостоящими и требуют больше памяти из-за операции объединения. Для родительско-дочерних конструкций существуют накладные расходы, поскольку они представляют собой отдельные документы, которые должны быть объединены во время запроса. Необходимо убедиться, что родительский элемент и все его дочерние элементы существуют в одном сегменте. Хранение документов с родительско-дочерними отношениями связано со сложностью реализации.

Я приведу пример, готовый к выполнению в ES 7

 curl -XDELETE "localhost:9200/project"

curl -XPUT "localhost:9200/project" 
-H 'Content-Type: application/json' 
-d'{
  "settings": {
    "number_of_shards": 1, "number_of_replicas": 0
  },
  "mappings": {
      "properties": {
        "project": { "type": "text" },
        "people": { "type": "text" },
        "active": { "type": "boolean" },
        "project_relations": {
          "type": "join",
          "relations": {
            "project": "people"
          }
        }
      }
  }
}'


curl -XPUT "localhost:9200/project/_bulk" 
-H 'Content-Type: application/json' 
-d'
{"index":{"_id":1}}
{"name":"ElasticSearch upgrade","project_relations":{"name":"project"}, "active": true}
{"index":{"_id":2}}
{"name":"Website","project_relations":{"name":"project"}, "active": true}
{"index":{"_id":3}}
{"name":"SQL Server migration","project_relations":{"name":"project"}, "active": false}
'

curl -XPUT "localhost:9200/project/_doc/4?routing=1" 
-H 'Content-Type: application/json' 
-d'
{"people":"Evaldas Buinauskas","project_relations":{"name":"people","parent":1}}
'

curl -XPOST "localhost:9200/project/_doc/5?routing=1" 
-H 'Content-Type: application/json' 
-d'
{"people":"xynon","project_relations":{"name":"people","parent":1}}
'
 

Маршрутизация должна соответствовать идентификатору проекта

    curl -XPOST "localhost:9200/project/_doc/6?routing=2" 
    -H 'Content-Type: application/json' 
    -d'
    {"people":"Harry scherer","project_relations":{"name":"people","parent":2}}
    '

curl -XPOST "localhost:9200/project/_doc/7?routing=2" 
-H 'Content-Type: application/json' 
-d'
{"people":"Darrel Simon","project_relations":{"name":"people","parent":2}}
'

curl -XPOST "localhost:9200/project/_doc/8?routing=3" 
-H 'Content-Type: application/json' 
-d'
{"people":"Juan Carlos Alafita","project_relations":{"name":"people","parent":3}}
'
 

Поиск людей, работающих над обновлением ElasticSearch, и проект активен

  curl -XGET "localhost:9200/project/_search" 
    -H 'Content-Type: application/json' 
    -d'
    {
      "query": {
        "has_parent": {
          "parent_type": "project",
          "query": { "bool": {"must": [  {"match": { "active": true } },  {"match": { "name": "ElasticSearch upgrade" } } ] }}
        }
      }
    }' | jq
    
 

Результаты:

 {
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "project",
        "_type": "_doc",
        "_id": "4",
        "_score": 1,
        "_routing": "1",
        "_source": {
          "people": "Evaldas Buinauskas",
          "project_relations": {
            "name": "people",
            "parent": 1
          }
        }
      },
      {
        "_index": "project",
        "_type": "_doc",
        "_id": "5",
        "_score": 1,
        "_routing": "1",
        "_source": {
          "people": "xynon",
          "project_relations": {
            "name": "people",
            "parent": 1
          }
        }
      }
    ]
  }
}
 

Поиск людей, работающих над миграцией SQL Server, и проект неактивен

    curl -XGET "localhost:9200/project/_search" 
    -H 'Content-Type: application/json' 
    -d'
    {
      "query": {
        "has_parent": {
          "parent_type": "project",
          "query": { "bool": {"must": [  {"match": { "active": false } },  {"match": { "name": "SQL Server migration" } } ] }}
        }
      }
    }
    ' | jq


curl -XGET "localhost:9200/project/_search" 
-H 'Content-Type: application/json' 
-d'
{
  "query": {
    "has_parent": {
      "parent_type": "project",
      "query": { "match_all": {} }
    }
  }
}'