Elasticsearch: полнотекстовый поиск и фильтрация по вложенному массиву объектов - PullRequest
1 голос
/ 10 апреля 2020

Существует задача создать таблицу GUI, построенную на основе данных из таблиц N-объединения в PostgreSQL. Эта таблица GUI подразумевает сортировку и фильтрацию с возможностью полнотекстового поиска.

Я хочу использовать elasti c для этой цели. Подготовили эту структуру данных дляasticsearch:

{
  did_user_read: true,
  view_info: {
      total: 1,
      users: [
          { name: 'John Smith', read_at: '2020-02-04 11:00:01', is_current_user: false },
          { name: 'Samuel Jackson', read_at: '2020-02-04 11:00:01', is_current_user: true },
      ],
  },
  is_favorite: true,
  has_attachments: true,
  from: { 
      short_name: 'You',  
      full_name: 'Chuck Norris',
      email: 'ch.norris@example.com', 
      is_current_user: true 
  },
  subject: 'The secret of the appearance of navel lints',
  received_at: '2020-02-04 11:00:01'
}

Посоветуйте, пожалуйста, как правильно проиндексировать эту структуру, чтобы можно было фильтровать и искать по вложенным объектам и по вложенным массивам объектов?

Например, , я хочу получить все записи по следующим критериям:

is_favorite IS false

AND

FULL_TEXT_SEARCH("sam jackson") 
   BY FIELDS 
    users.name,        -- inside of array(!) 
    from.full_name,
    from.short_name

AND

users.is_current_user IS NOT false

AND

ORDER BY received_at DESC

1 Ответ

0 голосов
/ 10 апреля 2020

Ваше отображение индекса эластичного поиска для вышеуказанной структуры данных должно быть:

Отображение

{
    "mappings": {
        "properties": {
            "did_user_read": {
                "type": "boolean"
            },
            "view_info": {
                "properties": {
                    "total": {
                        "type": "integer"
                    },
                    "users": {
                        "properties": {
                            "name": {
                                "type": "text"
                            },
                            "read_at": {
                                "type": "date",
                                "format": "date_hour_minute_second"
                            },
                            "is_current_user": {
                                "type": "boolean"
                            }
                        }
                    }
                }
            },
            "is_favorite": {
                "type": "boolean"
            },
            "has_attachments": {
                "type": "boolean"
            },
            "from": {
                "properties": {
                    "short_name": {
                        "type": "text"
                    },
                    "full_name": {
                        "type": "text"
                    },
                    "email": {
                        "type": "keyword"
                    },
                    "is_current_user": {
                        "type": "boolean"
                    }
                }
            },
            "subject": {
                "type": "text"
            },
            "received_at": {
                "type": "date",
                "format": "date_hour_minute_second"
            }
        }
    }
}

Теперь я проиндексировал несколько документов в том же формате, который вы дали в ваш пример.

Поисковый запрос на основе заданных критериев должен быть:

Поисковый запрос:

{
    "query": {
        "bool": {
            "filter": [
                {
                    "term": {
                        "is_favorite": false
                    }
                },
                {
                    "term": {
                        "view_info.users.is_current_user": true  
                    }
                }
            ],
            "must": {
                "multi_match": {
                    "query": "sam jackson",
                    "fields": [
                        "view_info.users.name",
                        "from.full_name",
                        "from.short_name"
                    ]
                }
            }


        }

    },
    "sort": [
    {
      "received_at": {
        "order": "desc"
      }
    }
  ]
}

Вывод

"hits": [
      {
        "_index": "topics",
        "_type": "_doc",
        "_id": "3",
        "_score": null,
        "_source": {
          "did_user_read": true,
          "view_info": {
            "total": 1,
            "users": [
              {
                "name": "John Smith",
                "read_at": "2020-02-04T11:00:01",
                "is_current_user": false
              },
              {
                "name": "Samuel Jackson",
                "read_at": "2020-02-04T11:00:01",
                "is_current_user": true
              }
            ]
          },
          "is_favorite": false,
          "has_attachments": true,
          "from": {
            "short_name": "You",
            "full_name": "Chuck Norris",
            "email": "ch.norris@example.com",
            "is_current_user": true
          },
          "subject": "The secret of the appearance of navel lints",
          "received_at": "2020-02-04T11:00:03"
        },
        "sort": [
          1580814003000
        ]
      },
      {
        "_index": "topics",
        "_type": "_doc",
        "_id": "2",
        "_score": null,
        "_source": {
          "did_user_read": true,
          "view_info": {
            "total": 1,
            "users": [
              {
                "name": "John Smith",
                "read_at": "2020-02-04T11:00:01",
                "is_current_user": false
              },
              {
                "name": "Samuel Jackson",
                "read_at": "2020-02-04T11:00:01",
                "is_current_user": true
              }
            ]
          },
          "is_favorite": false,
          "has_attachments": true,
          "from": {
            "short_name": "You",
            "full_name": "Chuck Norris",
            "email": "ch.norris@example.com",
            "is_current_user": true
          },
          "subject": "The secret of the appearance of navel lints",
          "received_at": "2020-02-04T11:00:01"
        },
        "sort": [
          1580814001000
        ]
      }
    ]

Объяснение:

На основе вашего запроса строится поисковый запрос:

  • is_favorite IS false and users.is_current_user IS NOT false

    Это делается с помощью запроса filter. Фильтр используется, когда мы хотим, чтобы наши документы удовлетворяли некоторым условиям, но они не влияют на оценку результатов поиска документов. Теперь, поскольку оба поля запроса являются булевыми, они не будут вносить вклад в вычисление для оценки, поскольку ответ будет либо да, либо нет.

  • FULL_TEXT_SEARCH("sam jackson") BY FIELDS users.name, -- inside of array(!) from.full_name, from.short_name

    Здесь мы хотим выполнить поиск sam jackson и они должны быть во всех 3 полях, поэтому используется match_phrase.

Эти три условия сохраняются в фильтре bool, поскольку к ним присоединяется условие AND

  • ORDER BY received_at DESC

    Для этого sort используется запрос

ПРИМЕЧАНИЕ : Вы должны изменить ваши данные, где datetime присутствует, как в read_at, receive_at. В настоящее время вы принимаете формат как 2020-02-04 11:00:01. Вам просто нужно немного изменить, чтобы при индексировании документов вasticsearch он принимал формат 2020-02-04T11: 00: 01 (вместо пробела используйте T), так какasticsearch принимает только набор форматов даты и времени. Вы можете ознакомиться с форматами, принятыми по дате / времени здесь https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-date-format.html

...