Лучший способ индексировать произвольные пары значений атрибутов при упругом поиске

Я пытаюсь проиндексировать документы по упругому поиску, которые имеют пары значений атрибутов. Примеры документов:

{
    id: 1,
    name: "metamorphosis",
    author: "franz kafka"
}

{
    id: 2,
    name: "techcorp laptop model x",
    type: "computer",
    memorygb: 4
}

{
    id: 3,
    name: "ss2014 formal shoe x",
    color: "black",
    size: 42,
    price: 124.99
}

Затем мне нужны запросы, такие как:

1. "author" EQUALS "franz kafka"
2. "type" EQUALS "computer" AND "memorygb" GREATER THAN 4
3. "color" EQUALS "black" OR ("size" EQUALS 42 AND price LESS THAN 200.00)

Каков наилучший способ хранения этих документов для их эффективного запроса? Должен ли я хранить их точно так, как показано в примерах? Или я должен хранить их как:

{
    fields: [
        { "type": "computer" },
        { "memorygb": 4 }
    ]
}

или как:

{
    fields: [
        { "key": "type", "value": "computer" },
        { "key": "memorygb", "value": 4 }
    ]
}

И как я должен сопоставить свои индексы, чтобы иметь возможность выполнять как мои запросы равенства, так и диапазон?

3 ответа

Если кто-то все еще ищет ответ, я написал пост о том, как индексировать произвольные данные в Elasticsearch, а затем выполнять поиск по определенным полям и значениям. Все это, не взрывая ваше индексное отображение.

Сообщение: http://smnh.me/indexing-and-searching-arbitrary-json-data-using-elasticsearch/

Короче, вам нужно будет создать специальный индекс, описанный в посте. Тогда вам нужно будет сгладить ваши данные, используя flattenData функция https://gist.github.com/smnh/30f96028511e1440b7b02ea559858af4. Затем сведенные данные можно безопасно проиндексировать в индексе Elasticsearch.

Например:

flattenData({
    id: 1,
    name: "metamorphosis",
    author: "franz kafka"
});

Будет производить:

[
    {
        "key": "id",
        "type": "long",
        "key_type": "id.long",
        "value_long": 1
    },
    {
        "key": "name",
        "type": "string",
        "key_type": "name.string",
        "value_string": "metamorphosis"
    },
    {
        "key": "author",
        "type": "string",
        "key_type": "author.string",
        "value_string": "franz kafka"
    }
]

А также

flattenData({
    id: 2,
    name: "techcorp laptop model x",
    type: "computer",
    memorygb: 4
});

Будет производить:

[
    {
        "key": "id",
        "type": "long",
        "key_type": "id.long",
        "value_long": 2
    },
    {
        "key": "name",
        "type": "string",
        "key_type": "name.string",
        "value_string": "techcorp laptop model x"
    },
    {
        "key": "type",
        "type": "string",
        "key_type": "type.string",
        "value_string": "computer"
    },
    {
        "key": "memorygb",
        "type": "long",
        "key_type": "memorygb.long",
        "value_long": 4
    }
]

Затем вы можете использовать сборку запросов Elasticsearch для запроса ваших данных. Каждый запрос должен указывать как ключ, так и тип значения. Если вы не уверены, какие ключи или типы имеют индекс, вы можете запустить агрегацию, чтобы выяснить это, это также обсуждается в посте.

Например, чтобы найти документ, где author == "franz kafka" вам нужно выполнить следующий запрос:

{
    "query": {
        "nested": {
            "path": "flatData",
            "query": {
                "bool": {
                    "must": [
                        {"term": {"flatData.key": "author"}},
                        {"match": {"flatData.value_string": "franz kafka"}}
                    ]
                }
            }
        }
    }
}

Найти документы где type == "computer" and memorygb > 4 вам нужно выполнить следующий запрос:

{
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "path": "flatData",
                        "query": {
                            "bool": {
                                "must": [
                                    {"term": {"flatData.key": "type"}},
                                    {"match": {"flatData.value_string": "computer"}}
                                ]
                            }
                        }
                    }
                },
                {
                    "nested": {
                        "path": "flatData",
                        "query": {
                            "bool": {
                                "must": [
                                    {"term": {"flatData.key": "memorygb"}},
                                    {"range": {"flatData.value_long": {"gt": 4}}}
                                ]
                            }
                        }
                    }
                }
            ]
        }
    }
}

Здесь, поскольку мы хотим, чтобы один и тот же документ соответствовал обоим условиям, мы используем внешний bool запрос с must пункт обертывания два nested запросы.

Elastic Search - это хранилище данных без схемы, которое позволяет динамически индексировать новые атрибуты и не имеет никакого влияния на производительность при наличии дополнительных полей. Ваше первое отображение абсолютно нормально, и вы можете иметь логические запросы вокруг ваших динамических атрибутов. Нет никакого преимущества в производительности, если сделать их вложенными полями, они в любом случае будут сглажены при индексации, например fields.type, fields.memorygb и т. Д.

Напротив, ваше последнее сопоставление, в котором вы пытаетесь сохранить пары "ключ-значение", будет влиять на производительность, поскольку вам придется запрашивать 2 разных индексированных поля, то есть где ключ = "memorygb" и значение =4

Посмотрите документацию о динамическом отображении:

Одной из наиболее важных особенностей Elasticsearch является его способность быть без схемы. Если объект является динамическим, не возникает никаких проблем с производительностью, возможность его отключения предоставляется в качестве механизма безопасности, поэтому "неправильно сформированные" объекты по ошибке не будут индексировать данные, которые мы не хотим индексировать.

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-object-type.html

Вам нужен отфильтрованный запрос, смотрите здесь:

Вы должны использовать запрос диапазона вместе с запросом на совпадение

Другие вопросы по тегам