Обучение ElasticSearch (2): запросы и агрегация Elasticsearch

Elasticsearch

1. Введение в поисковый API Elasticsearch

1. Обзор поискового API

  • Реализован запросный анализ данных, хранящихся в es, конечная точка — _search
  • Существует две основные формы запроса
    • URI Search
      • Простота в эксплуатации, удобно тестировать через командную строку
      • Содержит только часть синтаксиса запроса
    • Request Body Search
      • Полный синтаксис запроса Query DSL (Domain Specific Language), предоставляемый es

2. URI Search подробное объяснение и демонстрация

  • Поиск осуществляется через параметр запроса url, обычно используются следующие параметры:
    • q Указывает оператор запроса, синтаксис — синтаксис строки запроса.
    • Поле, которое будет запрошено по умолчанию, если поле не указано в df q, если не указано, es будет запрашивать все поля
    • сортировать сортировать
    • тайм-аут указывает период тайм-аута, по умолчанию не тайм-аут
    • форма, размер используется для подкачки

Query String Syntax

  • термин и фраза
    • путь альфреда эквивалентен способу альфреда ИЛИ
    • "альфред уэй" словесный запрос, порядок запроса
  • Пан запрос
    • Альфред эквивалентен сопоставлению термина во всех полях
  • указанное поле
    • name:alfred
  • Параметры группировки групп, используйте круглые скобки, чтобы указать правила сопоставления
    • (quick OR brown) AND fox
    • status:(active OR pending) title:(full text search)
PUT test_search_index
{
  "settings": {
    "index":{
        "number_of_shards": "1"
    }
  }
}

POST test_search_index/doc/_bulk
{"index":{"_id":"1"}}
{"username":"alfred way","job":"java engineer","age":18,"birth":"1990-01-02","isMarried":false}
{"index":{"_id":"2"}}
{"username":"alfred","job":"java senior engineer and java specialist","age":28,"birth":"1980-05-07","isMarried":true}
{"index":{"_id":"3"}}
{"username":"lee","job":"java and ruby engineer","age":22,"birth":"1985-08-07","isMarried":false}
{"index":{"_id":"4"}}
{"username":"alfred junior way","job":"ruby engineer","age":23,"birth":"1989-08-07","isMarried":false}
  • Далее мы сделаем фактический запрос.Сначала мы сделаем общий запрос.Смысл запроса в том, что все поля содержат документы Альфреда.
GET test_search_index/_search?q=alfred

{
  "took" : 29,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 3,
    "max_score" : 1.2039728,
    "hits" : [
      {
        "_index" : "test_search_index",
        "_type" : "doc",
        "_id" : "2",
        "_score" : 1.2039728,
        "_source" : {
          "username" : "alfred",
          "job" : "java senior engineer and java specialist",
          "age" : 28,
          "birth" : "1980-05-07",
          "isMarried" : true
        }
      },
      {
        "_index" : "test_search_index",
        "_type" : "doc",
        "_id" : "1",
        "_score" : 0.33698124,
        "_source" : {
          "username" : "alfred way",
          "job" : "java engineer",
          "age" : 18,
          "birth" : "1990-01-02",
          "isMarried" : false
        }
      },
      {
        "_index" : "test_search_index",
        "_type" : "doc",
        "_id" : "4",
        "_score" : 0.27601978,
        "_source" : {
          "username" : "alfred junior way",
          "job" : "ruby engineer",
          "age" : 23,
          "birth" : "1989-08-07",
          "isMarried" : false
        }
      }
    ]
  }
}
  • Давайте посмотрим, как es выполняет условия запроса
GET test_search_index/_search?q=alfred
{
  "profile":true
}
  • Запрос по полю
GET test_search_index/_search?q=username:alfred
  • Просто выполните любое из условий
GET test_search_index/_search?q=username:alfred way
{
  "profile":true
}
  • Теперь есть два способа изменить
GET test_search_index/_search?q=username:"alfred way"
{
  "profile":true
}

GET test_search_index/_search?q=username:(alfred way)
{
  "profile":true
}
  • логический оператор
    • И(&&), ИЛИ(||), НЕ(!)
    • name:(tom NOT lee)
    • Обратите внимание на прописные, а не на строчные
  • + - соответствуют must и must_not соответственно
    • name:(tom +lee -alfred)
    • + будет проанализирован как пробел в URL-адресе, можно будет использовать только результат после кодирования, то есть %2B
GET test_search_index/_search?q=username:alfred AND way
{
  "profile":true
}

GET test_search_index/_search?q=username:(alfred AND way)
{
  "profile":true
}

GET test_search_index/_search?q=username:(alfred NOT way)

GET test_search_index/_search?q=username:(alfred +way)
{
  "profile":true
}

GET test_search_index/_search?q=username:(alfred %2Bway)
{
  "profile":true
}
  • Запрос диапазона, поддерживает числа и дату
    • Метод записи интервала, используйте [] для закрытого интервала и {} для открытого интервала
    • Арифметическая запись
GET test_search_index/_search?q=username:alfred age:>26

GET test_search_index/_search?q=username:alfred AND age:>20

GET test_search_index/_search?q=birth:(>1980 AND <1990)
  • Подстановочный запрос
    • ? представляет один символ, * представляет 0 или более символов
    • Сопоставление с подстановочными знаками неэффективно и занимает много памяти, поэтому не рекомендуется его использовать.
    • Если нет особых требований, не ставьте ?/* на первое место.
GET test_search_index/_search?q=username:alf*
  • соответствие регулярному выражению
GET test_search_index/_search?q=username:/[a]?l.*/
  • Нечеткий соответствующий нечеткий запрос
    • name:roam~1
    • Сопоставьте слова, которые отличаются от roam на 1 символ, например пена бродит и т. д.
  • поиск близости
    • "fox quick"~5
    • Сравнение различий с точки зрения сроков
GET test_search_index/_search?q=username:alfed

GET test_search_index/_search?q=username:alfed~1

GET test_search_index/_search?q=username:alfd~2

GET test_search_index/_search?q=job:"java engineer"

GET test_search_index/_search?q=job:"java engineer"~1

GET test_search_index/_search?q=job:"java engineer"~2

3. Введение в Query DSL

  • Отправьте оператор запроса в es через тело http-запроса, в основном включая следующие параметры.
    • запрос — это запрос, соответствующий синтаксису Query DSL.
    • форма, размер
    • timeout
    • sort
    • ...
  • Язык запросов, определенный на основе JSON, в основном включает следующие два типа:
    • Запрос класса поля
      • Например, термин, совпадение, диапазон и т. д., запрашивайте только определенное поле.
    • Составной запрос
      • Например, логический запрос и т. д., содержащий один или несколько полевых запросов или операторов составного запроса.

4. Введение в запрос поля и запрос соответствия

  • Полевой запрос в основном включает следующие две категории:
    • полное текстовое совпадение
      • Для полнотекстового поиска полей текстового типа оператор запроса будет сначала сегментирован, например, match, match_phrase и другие типы запросов.
    • совпадение слов
      • Он не будет выполнять сегментацию слов в операторе запроса, а будет напрямую соответствовать инвертированному индексу поля, такому как термин, термины, диапазон и другие типы запросов.
GET test_search_index/_search
{
  "query": {
    "match": {
      "username": "alfred way"
    }
  }
}
  • Отношения соответствия между словами можно контролировать параметром оператора, варианты или и и
GET test_search_index/_search
{
  "query": {
    "match": {
      "username": {
        "query": "alfred way",
        "operator": "and"
      }
    }
  }
}
  • Количество слов, которые необходимо сопоставить, можно контролировать с помощью параметра Minimum_should_match.
GET test_search_index/_search
{
  "query": {
    "match": {
      "job": {
        "query": "java ruby engineer",
        "minimum_should_match": "3"
      }
    }
  }
}

5. Оценка релевантности

  • Оценка релевантности относится к степени релевантности между документом и оператором запроса, на английском языке это релевантность.
    • Список документов, соответствующих запросу, можно получить с помощью инвертированного индекса, так как же поместить документы, которые лучше всего соответствуют запросам пользователя, впереди?
    • Суть в задаче сортировки, а сортировка основана на показателе корреляции
  • Несколько важных концепций оценки корреляции заключаются в следующем:
    • Частота терминов (TF): частота слов, то есть количество раз, когда слово появляется в документе, чем выше частота слов, тем выше релевантность.
    • Частота документа (DF): частота документа, т. е. количество документов, в которых встречается слово.
    • Обратная частота документа (IDF): обратная частота документа, противоположная частоте документа, просто понимаемая как 1/DF, то есть чем меньше документов появляется слово, тем выше корреляция
    • Норма длины поля: чем короче документ, тем выше релевантность
  • В настоящее время ES в основном имеет две модели оценки корреляции, а именно:
    • Модель TF/IDF
    • Модель BM25: модель по умолчанию после 5.X

TF/IDF模型

  • Вы можете просмотреть конкретный метод расчета через параметр объяснения, но обратите внимание:
    • Оценка es рассчитывается в соответствии с осколком, то есть расчет оценки осколка не зависит друг от друга, поэтому при использовании объяснения обращайте внимание на количество осколков.
    • Этой проблемы можно избежать, установив количество осколков индекса равным 1.
GET test_search_index/_search
{
  "explain":true,
  "query": {
    "match": {
      "username": "alfred way"
    }
  }
}
  • В модели BM25 BM относится к лучшему совпадению, а 25 относится к методу расчета после повторения 25 слов, что является оптимизацией для TF/IDF.

6. match-phrase-query

  • Поиск полей, есть требования к порядку
GET test_search_index/_search
{
  "query": {
    "match_phrase": {
      "job": "java engineer"
    }
  }
}


GET test_search_index/_search
{
  "query": {
    "match_phrase": {
      "job": "engineer java"
    }
  }
}
  • Интервал между словами можно контролировать с помощью параметра slop.
GET test_search_index/_search
{
  "query": {
    "match_phrase": {
      "job": {
        "query": "java engineer",
        "slop": "2"
      }
    }
  }
}

7. query-string-query

  • Аналогично запросу параметра q в поиске URI
GET test_search_index/_search
{
  "profile":true,
  "query":{
    "query_string": {
      "default_field": "username",
      "query": "alfred AND way"
    }
  }
}

GET test_search_index/_search
{
  "profile":true,
  "query": {
    "query_string": {
      "fields": [
        "username",
        "job"
      ],
      "query": "alfred OR (java AND ruby)"
    }
  }
}

8. simple-query-string-query

  • Аналогичен строке запроса, но игнорирует неправильный синтаксис запроса и поддерживает только частичный синтаксис запроса.
GET test_search_index/_search
{
  "profile":true,
  "query":{
    "simple_query_string": {
      "query": "alfred +way \"java",
      "fields": ["username"]
    }
  }
}

GET test_search_index/_search
{
  "query":{
    "query_string": {
      "default_field": "username",
      "query": "alfred +way \"java"
    }
  }
}

9. term-terms-query

  • Запрашивать оператор запроса как целое слово, то есть не выполнять обработку сегментации слов в операторе запроса.
GET test_search_index/_search
{
  "query":{
    "term":{
      "username":"alfred"
    }
  }
}

GET test_search_index/_search
{
  "query":{
    "term":{
      "username":"alfred way"
    }
  }
}
  • термины: один входящий несколько запросов
G`ET test_search_index/_search
{
  "query": {
    "terms": {
      "username": [
        "alfred",
        "way"
      ]
    }
  }
}

10. range-query

  • Запросы диапазона в основном предназначены для числовых типов и типов даты.
GET test_search_index/_search
{
  "query":{
    "range": {
      "age": {
        "gte": 10,
        "lte": 30
      }
    }
  }
}

GET test_search_index/_search
{
  "query":{
    "range": {
      "birth": {
        "gte": "1980-01-01"
      }
    }
  }
}
  • Более удобный расчет дат
GET test_search_index/_search
{
  "query":{
    "range": {
      "birth": {
        "gte": "now-30y"
      }
    }
  }
}

GET test_search_index/_search
{
  "query":{
    "range": {
      "birth": {
        "gte": "2010||-20y"
      }
    }
  }
}

11. Введение в составной запрос и ConstantScore

  • Составные запросы относятся к типам, которые содержат классы полей или составные запросы, включая следующие категории:
    • constant_score_query
    • bool query
    • dis_max query
    • function_score_query
    • boosting query

Constant Score Query

  • Запрос присваивает своей внутренней оценке документа результатов запроса значение 1 или значение boost.
    • В основном используется для реализации пользовательских оценок в сочетании с логическими запросами.
GET test_search_index/_search
{
  "query":{
    "constant_score": {
      "filter": {
        "match":{
          "username":"alfred"
        }
      }
    }
  }
}

GET test_search_index/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "constant_score": {
            "filter": {
              "match": {
                "job": "java"
              }
            }
          }
        },
        {
          "constant_score": {
            "filter": {
              "match": {
                "job": "ruby"
              }
            }
          }
        }
      ]
    }
  }
}

12. bool-query

  • Логический запрос состоит из одного или нескольких логических предложений, в основном из следующих четырех:
    • фильтр: фильтровать только те документы, которые соответствуют условиям, не вычислять показатель релевантности
    • must: документ должен соответствовать всем условиям в must, что влияет на оценку релевантности.
    • must_not: документ не должен соответствовать всем условиям в must_not
    • должен: документ может соответствовать условиям в должен, что повлияет на оценку релевантности

Filter

  • Запрос «Фильтр» фильтрует только те документы, которые соответствуют условиям, и не вычисляет показатель релевантности.
    • es будет иметь интеллектуальный кеш для фильтра, поэтому эффективность его выполнения очень высока.
    • При выполнении простого запроса на сопоставление без учета оценки рекомендуется использовать фильтр вместо запроса и т. д.
GET test_search_index/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "username": "alfred"
          }
        }
      ]
    }
  }
}

Must

GET test_search_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "username": "alfred"
          }
        },
        {
          "match": {
            "job": "specialist"
          }
        }
      ]
    }
  }
}

Must_Not

GET test_search_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "job": "java"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "job": "ruby"
          }
        }
      ]
    }
  }
}

should

  • Если документ содержит только должно, он должен соответствовать хотя бы одному условию.
    • Minimum_should_match может управлять количеством или процентом выполненных условий.
GET test_search_index/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "username": "junior"
          }
        },
        {
          "match": {
            "job": "ruby"
          }
        }
      ]
    }
  }
}

GET test_search_index/_search
{
  "query": {
    "bool": {
      "should": [
        {"term": {"job": "java"}},
        {"term": {"job": "ruby"}},
        {"term": {"job": "specialist"}}
      ],
      "minimum_should_match": 2
    }
  }
}
  • Когда включены оба параметра: must и must, документ не обязательно соответствует условиям, указанным в «должен», но если условия соблюдены, оценка релевантности будет увеличена.
GET test_search_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "username": "alfred"
          }
        }
      ],
      "should": [
        {
          "term": {
            "job": "ruby"
          }
        }
      ]
    }
  }
}
  • Когда оператор запроса находится в контексте запроса или фильтра, результаты выполнения es будут другими.
    • запрос: найти документ, который лучше всего соответствует формулировке запроса, оценить и отсортировать все документы по релевантности.
    • фильтр: найти документы, соответствующие запросу

13. count and source filtering

  • Получить количество документов, соответствующих условиям, конечная точка _count
GET test_search_index/_count
{
  "query":{
    "match":{
      "username": "alfred"
    }
  }
}

source filtering

  • Отфильтровать поля в _source в возвращаемом результате
GET test_search_index/_search

GET test_search_index/_search?_source=username

GET test_search_index/_search
{
  "_source": false
}

GET test_search_index/_search
{
  "_source": ["username","age"]
}

GET test_search_index/_search
{
  "_source": {
    "includes": "*i*",
    "excludes": "birth"
  }
}

2. Глубокое понимание механизма работы поиска в Elasticsearch.

1. Query Then Fetch

  • Когда поиск выполняется, он фактически работает в два этапа.
    • Этап запроса
    • Стадия выборки

Query阶段

Fetch阶段

2. Оценка релевантности

  • Оценка корреляции независима между осколками и осколками, что означает, что эквивалент IDF одного и того же термина отличается в разных осколках, а показатель корреляции документа связан с осколком, в котором он находится.
  • Когда количество документов невелико, оценка корреляции будет серьезно неточной.
POST test_search_relevance/doc
{
  "name":"hello"
}

POST test_search_relevance/doc
{
  "name":"hello,world"
}

POST test_search_relevance/doc
{
  "name":"hello,world!a beautiful world"
}

GET test_search_relevance/_search
{
  "explain": true, 
  "query": {
    "match":{
      "name":"hello"
    }
  }
}
  • Есть два пути решения проблемы:
    • Во-первых, чтобы полностью устранить проблему, установите количество осколков равным 1. Это решение можно рассмотреть, когда количество документов невелико, например количество документов исчисляется миллионами или десятками миллионов.
    • Второй — использовать метод запроса DFS Query-then-Fetch.
  • Функция DFS Query-then-Fetch предназначена для полного пересчета оценки корреляции после получения всех документов. Она потребляет больше ресурсов ЦП и памяти, а производительность выполнения относительно низкая. Как правило, ее использовать не рекомендуется. Способ применения следующий:
GET test_search_relevance/_search?search_type=dfs_query_then_fetch
{
  "query": {
    "match":{
      "name":"hello"
    }
  }
}

3. sorting doc values fielddata

  • По умолчанию es будет использовать сортировку по показателю корреляции.Пользователи могут сами установить правила сортировки, задав параметр сортировки.
GET test_search_index/_search
{
  "query":{
    "match": {
      "username": "alfred"
    }
  },
  "sort":{
    "birth":"desc"
  }
}

GET test_search_index/_search
{
  "query":{
    "match": {
      "username": "alfred"
    }
  },
  "sort": [
    {
      "birth": "desc"
    },
    {
      "_score": "desc"
    },
    {
      "_doc": "desc"
    }
  ]
}
  • Сортировка по строкам особенная, потому что es имеет два типа: текст и ключевое слово.
    • Сортировка по типу текста вызовет ошибку
    • Сортировка по типу ключевого слова возвращает ожидаемый результат
GET test_search_index/_search
{
  "sort":{
    "username.keyword":"desc"
  }
}

Сортировать

  • Суть процесса сортировки заключается в процессе сортировки исходного содержимого поля, в этом процессе инвертированный индекс не может играть роли, и необходимо использовать прямой индекс, то есть исходное содержимое поля может быть быстро получить через идентификатор документа и поля.
  • es предоставляет 2 способа реализовать это:
    • fielddata отключен по умолчанию
    • значения doc включены по умолчанию, кроме текстовых типов

Fielddata

  • Полевые данные отключены по умолчанию и могут быть включены через следующие API:
    • В настоящее время строки сортируются в соответствии с термином после сегментации слова, и результаты часто трудно оправдать ожидания.
    • Как правило, он включается, когда анализ агрегации выполняется для сегментации слова.
PUT test_search_index/_mapping/doc
{
  "properties": {
    "job":{
      "type":"text",
      "fielddata": true
    }
  }
} 

Doc Values

  • Doc Values ​​включены по умолчанию и могут быть отключены при создании индекса:
    • Если вы хотите включить Doc Values ​​позже, вам нужно выполнить операцию переиндексации
PUT test_doc_values/_mapping/doc
{
  "properties": {
    "username": {
      "type": "keyword",
      "doc_values": false
    },
    "hobby": {
      "type": "keyword"
    }
  }
}

docvalue_fields

  • Через это поле вы можете получить содержимое, хранящееся в значениях fielddata или doc.
GET test_search_index/_search
{
  "docvalue_fields": [
    "username",
    "username.keyword",
    "age"
  ]
}

4. Пейджинг и обход - fromsize

  • es предоставляет 3 способа решения проблемы подкачки и обхода:
    • from/size
      • from указывает начальную позицию
      • size указывает общее количество приобретений
    • scoll
    • search_after
  • Глубокое пейджинг — классическая проблема: как получить первую 1000 документов в случае шардированного хранилища данных?
    • При получении 990~1000 документов сначала будет получено 1000 документов в каждом сегменте, затем результаты всех сегментов будут агрегированы Координационным узлом, а затем будут отсортированы и получены первые 1000 документов.
    • Чем глубже количество страниц, тем больше документов обрабатывается, тем больше памяти занято и больше времени тратится, старайтесь избегать глубокого пейджинга, es ограничен 10 000 штук данных через index.max_result_window
GET test_search_index/_search
{
  "from":0,
  "size":2
}

GET test_search_index/_search
{
  "from":10000,
  "size":2
}

5. Пейджинг и обход-прокрутка

  • Пройдите через API набора документов и используйте моментальный снимок, чтобы избежать проблемы глубокого пейджинга.
    • Невозможно использовать для поиска в реальном времени, поскольку данные не в реальном времени.
    • Старайтесь не использовать сложные условия сортировки, использование _doc является наиболее эффективным
    • Это немного сложно использовать
  • Первый шаг — инициировать поиск по прокрутке.
    • es создает снимок коллекции идентификаторов документов в соответствии с условиями запроса после получения запроса.
GET test_search_index/_search?scroll=5m
{
  "size":1  指明每次scroll返回的文档数
}
  • Второй шаг вызывает API поиска прокрутки, чтобы получить коллекцию документов.
    • Продолжайте повторять вызов, пока возвращаемый массив hits.hits не станет пустым, и остановитесь.
POST _search/scroll
{
  "scroll" : "5m", 
  "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAABswWX3FLSTZFOF9URFdqWHlvX3gtYmhtdw=="
}
  • Поскольку это моментальный снимок, новые документы не могут быть получены.
PUT test_search_index/doc/10
{
  "username":"doc10"
}
  • Слишком много вызовов прокрутки займут много памяти, вы можете использовать clear API, чтобы удалить слишком много снимков прокрутки.

    DELETE _search/scroll/_all

6. Пейджинг и обход - search_after

  • Избегайте проблем с производительностью глубокого разбиения по страницам и предоставляйте функцию поиска документов на следующей странице в реальном времени.
    • Минус в том, что нельзя использовать параметр from, то есть нельзя указать количество страниц
    • Только следующая страница, а не предыдущая страница
    • Простой в использовании
  • Первый шаг — обычный поиск, но укажите значение сортировки и убедитесь, что это значение уникально.
GET test_search_index/_search
{
  "size":1,
  "sort":{
    "age":"desc",
    "_id":"desc"
  }
}
  • Второй шаг — использовать значение сортировки последнего документа на предыдущем шаге для запроса.
GET test_search_index/_search
{
  "size":1,
  "search_after":[23,"4"],
  "sort":{
    "age":"desc",
    "_id":"desc"
  }
}

Сценарии применения

  • От / размер: вам нужно получить некоторые документы вверху в режиме реального времени, и вам нужно свободно перелистывать страницы
  • Прокрутка: требуется полная документация, например возможность экспорта всех данных.
  • Search_After: Требуются все документы, свободное перелистывание страниц не требуется

3. Введение в анализ агрегации Elasticsearch

1. Введение в совокупный анализ

  • Поисковые системы используются для ответа на такие вопросы, как:
    • Подскажите, пожалуйста, все заказы с адресом в Шанхае?
    • Скажите, пожалуйста, все заказы, созданные за последний 1 день, но не оплаченные?
  • Агрегированный анализ может ответить на такие вопросы, как:
    • Скажите, пожалуйста, какой ежедневный объем заказов за последнюю неделю?
    • Скажите, пожалуйста, какая средняя сумма заказа в день за последний 1 месяц?
    • Скажите, пожалуйста, какие продукты входят в топ-5 самых популярных товаров, проданных за последние шесть месяцев?

Совокупный анализ

  • Агрегационный анализ, Aggregation на английском языке, — это функция, предоставляемая es для статистического анализа данных es в дополнение к функции поиска.
    • Богатый функциями, он предоставляет различные методы анализа, такие как Bucket, Metric и Pipeline, которые могут удовлетворить большинство потребностей анализа.
    • Высокая производительность в режиме реального времени, все результаты вычислений возвращаются вовремя, а системы больших данных, такие как Hadoop, обычно работают в режиме T+1.

Классификация

  • Для простоты понимания es делит анализ агрегации на следующие четыре категории:
    • Bucket, тип сегмента, аналогичный синтаксису GROUP BY в SQL.
    • Метрика, тип анализа метрики, например расчет максимального значения, минимального значения, среднего значения и т. д.
    • Конвейерный, тип конвейерного анализа, повторный анализ на основе агрегированных результатов анализа предыдущего уровня
    • Матрица, тип матричного анализа

2. Анализ агрегации показателей

POST test_search_index/doc/_bulk
{"index":{"_id":"1"}}
{"username":"alfred way","job":"java engineer","age":18,"birth":"1990-01-02","isMarried":false,"salary":10000}
{"index":{"_id":"2"}}
{"username":"tom","job":"java senior engineer","age":28,"birth":"1980-05-07","isMarried":true,"salary":30000}
{"index":{"_id":"3"}}
{"username":"lee","job":"ruby engineer","age":22,"birth":"1985-08-07","isMarried":false,"salary":15000}
{"index":{"_id":"4"}}
{"username":"Nick","job":"web engineer","age":23,"birth":"1989-08-07","isMarried":false,"salary":8000}
{"index":{"_id":"5"}}
{"username":"Niko","job":"web engineer","age":18,"birth":"1994-08-07","isMarried":false,"salary":5000}
{"index":{"_id":"6"}}
{"username":"Michell","job":"ruby engineer","age":26,"birth":"1987-08-07","isMarried":false,"salary":12000}
  • В основном делятся на следующие две категории:
    • Анализ одного значения, вывод только одного результата анализа
      • мин., макс., среднее, сумма
      • cardinality
    • Многозначный анализ, вывод нескольких результатов анализа
      • статистика, предполагаемая статистика
      • процентиль, процентильный ранг
      • top hits

Min

  • Возвращает минимальное значение числового поля
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "min_age":{
      "min": {
        "field": "age"
      }
    }
  }
}

Max

  • Возвращает максимальное значение числового поля
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "max_age":{
      "max": {
        "field": "age"
      }
    }
  }
}

Avg

  • Возвращает среднее значение числового поля
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "avg_age":{
      "avg": {
        "field": "age"
      }
    }
  }
}

Sum

  • Возвращает сумму числового поля класса
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "sum_age":{
      "sum": {
        "field": "age"
      }
    }
  }
}
  • Возврат нескольких агрегированных результатов одновременно
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "min_age": {
      "min": {
        "field": "age"
      }
    },
    "max_age": {
      "max": {
        "field": "age"
      }
    },
    "avg_age": {
      "avg": {
        "field": "age"
      }
    },
    "sum_age": {
      "sum": {
        "field": "age"
      }
    }
  }
}

Cardinality

  • Кардинальность, которая означает потенциал набора или кардинальность, относится к количеству различных значений, аналогично концепции подсчета отдельных элементов в SQL.
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "count_of_job":{
      "cardinality": {
        "field": "job.keyword"
      }
    }
  }
}

Stats

  • Возвращает ряд числовых статистических данных, включая минимальное, максимальное, среднее, сумму и количество
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "stats_age":{
      "stats": {
        "field": "age"
      }
    }
  }
}

Extended Stats

  • Расширение для статистики, чтобы включить дополнительные статистические данные, такие как дисперсия, стандартное отклонение и т. д.
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "exstats_salary":{
      "extended_stats": {
        "field": "salary"
      }
    }
  }
}

Percentile

  • Процентильная статистика
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "per_salary":{
      "percentiles": {
        "field": "salary"
      }
    }
  }
}

GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "per_age": {
      "percentiles": {
        "field": "salary",
        "percents": [
          95,
          99,
          99.9
        ]
      }
    }
  }
}

Percentile Rank

  • Процентильная статистика
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "per_salary": {
      "percentile_ranks": {
        "field": "salary",
        "values": [
          11000,
          30000
        ]
      }
    }
  }
}

Top Hits

  • Обычно он используется для получения списка наиболее подходящих документов в корзине после группировки, то есть подробных данных.
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job.keyword",
        "size": 10
      },
      "aggs": {
        "top_employee": {
          "top_hits": {
            "size": 10,
            "sort": [
              {
                "age": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

3. Анализ агрегации ведра

  • Ведро, что означает ведро, то есть назначение документов разным ведрам в соответствии с определенными правилами для достижения цели классификации и анализа.
  • В соответствии со стратегией распределения корзин Bucket, общий анализ агрегации корзин выглядит следующим образом:
    • Terms
    • Range
    • Date Range
    • Histogram
    • Date Histogram

Terms

  • Эта стратегия группирования является самой простой, и сегменты делятся непосредственно в соответствии с термином.Если это текстовый тип, он будет разделен на сегменты в соответствии с результатом сегментации слов.
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job",
        "size": 5
      }
    }
  }
}

Range

  • Установите правила корзины в соответствии с указанным диапазоном значений
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "salary_range": {
      "range": {
        "field": "salary",
        "ranges": [
          {
            "key":"<10000",
            "to": 10000
          },
          {
            "from": 10000,
            "to": 20000
          },
          {
            "key":">20000",
            "from": 20000
          }
        ]
      }
    }
  }
}

Date Range

  • Установите правила группирования, указав диапазон дат
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "date_range": {
      "range": {
        "field": "birth",
        "format": "yyyy",
        "ranges": [
          {
            "from":"1980",
            "to": "1990"
          },
          {
            "from": "1990",
            "to": "2000"
          },
          {
            "from": "2000"
          }
        ]
      }
    }
  }
}

Histogram

  • Гистограмма, которая разбивает данные с помощью стратегии фиксированных интервалов.
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "salary_hist":{
      "histogram": {
        "field": "salary",
        "interval": 5000,
        "extended_bounds": {
          "min": 0,
          "max": 40000
        }
      }
    }
  }
}

Date Histogram

  • Гистограммы или гистограммы для дат являются наиболее часто используемыми типами статистического анализа при анализе данных временных рядов.
GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "by_year":{
      "date_histogram": {
        "field": "birth",
        "interval": "year",
        "format":"yyyy"
      }
    }
  }
}

4. Сегментный и агрегированный анализ метрик

  • Анализ агрегации сегментов позволяет проводить дальнейший анализ, добавляя субанализ, который может быть сегментом или метрикой, что также делает возможности агрегированного анализа чрезвычайно мощными.
  • ведро за ведром
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job.keyword",
        "size": 10
      },
      "aggs": {
        "age_range": {
          "range": {
            "field": "age",
            "ranges": [
              {
                "to": 20
              },
              {
                "from": 20,
                "to": 30
              },
              {
                "from": 30
              }
            ]
          }
        }
      }
    }
  }
}
  • Анализ данных после группировки
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job.keyword",
        "size": 10
      },
      "aggs": {
        "salary": {
          "stats": {
            "field": "salary"
          }
        }
      }
    }
  }
}

5. Агрегационный анализ конвейера

  • Результаты анализа агрегации повторно агрегируются и анализируются, а цепные вызовы поддерживаются для ответа на следующие вопросы:
    • Каков средний ежемесячный объем продаж заказов?
  • Результаты анализа конвейера будут выведены в исходные результаты, которые разделены на следующие две категории в зависимости от места вывода:
    • Родительские результаты встроены в существующие совокупные результаты анализа
      • Derivative
      • Moving Average
      • Cumulative Sum
    • Результаты одноуровневого анализа находятся на том же уровне, что и результаты совокупного анализа.
      • Max/Min/Avg/Sum Bucket
      • Stats/Extended Stats Bucket
      • Percentiles Bucket

Min Bucket

GET test_search_index/_search
{
  "size":0,
  "aggs":{
    "jobs":{
      "terms": {
        "field": "job.keyword",
        "size": 10
      },
      "aggs":{
        "avg_salary":{
          "avg": {
            "field": "salary"
          }
        }
      }
    },
    "min_salary_by_job":{
      "min_bucket": {
        "buckets_path": "jobs>avg_salary"
      }
    }
  }
} 

Derivative

  • Вычислить производную от значения Bucket
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "birth": {
      "date_histogram": {
        "field": "birth",
        "interval": "year",
        "min_doc_count": 0
      },
      "aggs": {
        "avg_salary": {
          "avg": {
            "field": "salary"
          }
        },
        "derivative_avg_salary": {
          "derivative": {
            "buckets_path": "avg_salary"
          }
        }
      }
    }
  }
}

Moving Average

  • Рассчитать скользящее среднее значений корзины

Cumulative Sum

  • Рассчитать совокупную сумму стоимости ведра

6. Сфера действия

  • Объемом анализа агрегации es по умолчанию является набор результатов запроса, и его объем можно изменить следующими способами:
    • filter
    • post_filter
    • global

filter

  • Установите условия фильтра для совокупного анализа, тем самым изменив область действия без изменения общего оператора запроса.
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "jobs_salary_small": {
      "filter": {
        "range": {
          "salary": {
            "to": 10000
          }
        }
      },
      "aggs": {
        "jobs": {
          "terms": {
            "field": "job.keyword"
          }
        }
      }
    },
    "jobs": {
      "terms": {
        "field": "job.keyword"
      }
    }
  }
}

post_filter

  • Работает при фильтрации текста, но вступает в силу после совокупного анализа
GET test_search_index/_search
{
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job.keyword"
      }
    }
  },
  "post_filter": {
    "match":{
      "job.keyword":"java engineer"
    }
  }
}

global

  • Игнорировать условия фильтра запроса и анализировать на основе всех документов
GET test_search_index/_search
{
  "query": {
    "match": {
      "job.keyword": "java engineer"
    }
  },
  "aggs": {
    "java_avg_salary": {
      "avg": {
        "field": "salary"
      }
    },
    "all": {
      "global": {},
      "aggs": {
        "avg_salary": {
          "avg": {
            "field": "salary"
          }
        }
      }
    }
  }
}

7. Сортировка

  • Вы можете использовать встроенные ключевые данные для сортировки, например:
    • _count количество документов
    • _key сортируется по значению ключа
GET test_search_index/_search
{
  "size": 0,
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job.keyword",
        "size": 10,
        "order": [
          {
            "avg_salary": "desc"
          }
        ]
      },
      "aggs": {
        "avg_salary": {
          "avg": {
            "field": "salary"
          }
        }
      }
    }
  }
}

4. Моделирование данных в Elasticsearch

1. Введение в моделирование данных

  • Английский — Data Modeling, то есть процесс создания модели данных.
  • Модель данных
    • Инструмент и метод абстрактного описания реального мира
    • Бизнес-правила описываются в виде абстрактных сущностей и связей между сущностями, чтобы реализовать отображение реального мира.

процесс моделирования данных

  • концептуальная модель
    • Определите основные требования и границы области применения системы, сущностей проекта и взаимосвязей между сущностями.
  • логическая модель
    • Далее разберитесь с бизнес-требованиями и определите атрибуты, отношения и ограничения каждой сущности и т. д.
  • физическая модель
    • В сочетании с конкретными продуктами баз данных окончательное определение определяется исходя из требований к производительности чтения и записи и т. д.
    • MySQL, MongoDB, эластичный поиск и т. д.
    • третья нормальная форма

2. Введение в конфигурацию моделирования данных ES

  • ES — это система хранения, реализованная на основе инвертированного индекса на основе Lucene, и не следует парадигмальным соглашениям в реляционных базах данных.

Связанные настройки поля Mapping

  • enbaled
    • true | false
    • Только магазин, а не поиск или сводная аналитика
  • index
    • true | false
    • нужно ли строить инвертированный индекс
  • index_options
    • docs | freqs | positions | offsets
    • Какая информация хранится об инвертированном индексе
  • norms
    • true | false
    • Сохранять ли параметры, связанные с нормализацией, если поле используется только для фильтрации и анализа агрегации, его можно отключить.
  • doc_values
    • true | false
    • Включить ли doc_values ​​для анализа сортировки и агрегации
  • field_data
    • false | true
    • Следует ли запускать fielddata для текстового типа для реализации анализа сортировки и агрегирования
  • store
    • false | true
    • сохранять ли значение поля
  • coerce
    • true | false
    • Включить ли автоматическое преобразование типов данных, таких как строка в число, с плавающей запятой в целое число и т. д.
  • мультиполя
    • Гибкое использование многофункциональных функций для решения разнообразных бизнес-задач
  • dynamic
    • true | false | strict
    • Управление автоматическим обновлением карт
  • data_detection
    • true | false
    • Следует ли автоматически распознавать тип даты

Процесс установки

  • Какой это тип?
    • Тип строки
    • тип перечисления
    • Числовой тип
    • другие типы
  • Вам нужно искать?
    • Нет необходимости извлекать, сортировать, агрегировать и анализировать поля вообще
      • включено установлено значение false
    • Поля, которые не нужно искать
      • индекс установлен в ложь
    • Для извлекаемых полей вы можете установить требуемую емкость хранилища с помощью следующей конфигурации.
      • Комбинация index_options должна быть установлена
      • Нормы можно отключить, если не требуются нормализованные данные.
  • Вам нужен анализ сортировки и агрегации?
    • doc_values ​​имеет значение false
    • fielddata имеет значение false
  • Его нужно хранить отдельно?
    • Нужно ли мне хранить данные для текущего поля специально?

3. Пример моделирования данных ES

  • Сообщения в блоге blog_index
    • заглавие
    • дата публикацииpublish_date
    • авторавтор
    • Аннотация
    • содержание
    • URL-адрес сетевого адреса
PUT blog_index
{
  "mappings": {
    "doc": {
      "_source": {
        "enabled": false
      },
      "properties": {
        "title": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 100
            }
          },
          "store": true
        },
        "publish_date": {
          "type": "date",
          "store": true
        },
        "author": {
          "type": "keyword",
          "ignore_above": 100, 
          "store": true
        },
        "abstract": {
          "type": "text",
          "store": true
        },
        "content": {
          "type": "text",
          "store": true
        },
        "url": {
          "type": "keyword",
          "doc_values":false,
          "norms":false,
          "ignore_above": 100, 
          "store": true
        }
      }
    }
  }
}
  • Запрос
GET blog_index/_search
{
  "stored_fields": ["title","publish_date","author","abstract","url"], 
  "query": {
    "match": {
      "content": "blog"
    }
  },
  "highlight": {
    "fields":{
      "content": {}
    }
  }
}

4. Nested_Object

  • ES плохо справляется с реляционными отношениями в реляционных базах данных.Например, ассоциация blog_id между таблицей article blog и комментарием в таблице комментариев может быть решена в ES в замаскированной форме следующими двумя способами.
    • Nested Object
    • Parent/Child

Обработка ассоциативных отношений

  • Идентификатор статьи blog_id
  • прокомментировал имя пользователя
  • дата комментария дата
  • Содержание комментария
DELETE blog_index_nested
PUT blog_index_nested
{
"mappings": {
  "doc":{
    "properties": {
      "title":{
        "type": "text",
        "fields": {
          "keyword":{
            "type":"keyword",
            "ignore_above": 100
          }
        }
      },
      "publish_date":{
        "type":"date"
      },
      "author":{
        "type":"keyword",
        "ignore_above": 100
      },
      "abstract":{
          "type": "text"
        },
        "url":{
          "enabled":false
        },
        "comments":{
          "type":"nested", 
          "properties": {
            "username":{
              "type":"keyword",
              "ignore_above":100
            },
            "date":{
              "type":"date"
            },
            "content":{
              "type":"text"
            }
          }
        }
      }
    }
  }
}

PUT blog_index_nested/doc/2
{
  "title": "Blog Number One",
  "author": "alfred",
  "comments": [
    {
      "username": "lee",
      "date": "2017-01-02",
      "content": "awesome article!"
    },
    {
      "username": "fax",
      "date": "2017-04-02",
      "content": "thanks!"
    }
  ]
}

GET blog_index_nested/_search
{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "comments.username": "lee"
              }
            },
            {
              "match": {
                "comments.content": "thanks"
              }
            }
          ]
        }
      }
    }
  }
}

5. Parent_Child

  • ES также предоставляет метод реализации, аналогичный соединению в реляционных базах данных, который реализуется с использованием типа данных соединения.
PUT blog_index_parent_child
{
  "mappings": {
    "doc": {
      "properties": {
        "join": {
          "type": "join",
          "relations": {
            "blog": "comment"
          }
        }
      }
    }
  }
}

PUT blog_index_parent_child/doc/1
{
  "title":"blog",
  "join":"blog"  指明父类型
}

PUT blog_index_parent_child/doc/2
{
  "title":"blog2",
  "join":"blog"
}
PUT blog_index_parent_child/doc/comment-1?routing=1  指明routing值,确保父子文档在一个分片上,一般使用父文档Id
{
  "comment":"comment world",
  "join":{
    "name":"comment",  指明子类型
    "parent":1  指明父文档Id
  }
}


PUT blog_index_parent_child/doc/comment-2?routing=2
{
  "comment":"comment hello",
  "join":{
    "name":"comment",
    "parent":2
  }
}
  • Общие синтаксисы запросов включают следующее:
    • parent_id: возвращает дочерний документ родительского документа.
    • has_child: возвращает родительский документ, содержащий дочерний документ.
    • has_parent: возвращает дочерний документ, содержащий родительский документ.
GET blog_index_parent_child/_search
{
  "query":{
    "parent_id":{
      "type":"comment",
      "id":"2"
    }
  }
}
GET blog_index_parent_child/_search
{
  "query":{
    "has_child": {
      "type": "comment",
      "query": {
        "match": {
          "comment": "world"
        }
      }
    }
  }
}
GET blog_index_parent_child/_search
{
  "query":{
    "has_parent": {
      "parent_type": "blog",
      "query": {
        "match": {
          "title": "blog"
        }
      }
    }
  }
}

6. nested_vs_parent_child

nested object

  • Плюсы: документы хранятся вместе, поэтому скорость чтения высокая.
  • Недостаток: при обновлении родительского или дочернего документа необходимо обновить весь документ.
  • Сценарий: вложенные документы периодически обновляются, а запросы выполняются часто.

parent child

  • Преимущества: родительские и дочерние документы могут обновляться независимо, не затрагивая друг друга.
  • Недостатки: для поддержания отношения соединения часть памяти должна быть занята, а производительность чтения низкая.
  • Сценарий: вложенные документы часто обновляются

Для решения проблемы рекомендуется выбирать максимально вложенный объект.

7. reindex

  • Относится к процессу восстановления всех данных, который обычно происходит в следующих ситуациях:
    • Изменения в настройках сопоставления, такие как изменения типа поля, обновления словаря токенизатора и т. д.
    • Изменения в настройках индекса, такие как изменение количества осколков и т. д.
    • Перенести данные
  • ES предоставляет готовый API для выполнения работы.
    • _update_by_query перестраивает существующий индекс
    • _reindex перестраивает другие индексы
POST blog_index/_update_by_query?conflicts=proceed

POST _reindex
{
  "source": {
    "index": "blog_index"
  },
  "dest": {
    "index": "blog_new_index"
  }
}
  • На время восстановления данных влияет размер исходного индексного документа. Чем больше размер, тем больше времени это занимает. В этом случае его нужно выполнить асинхронно, установив для параметра url wait_for_completion значение false. ES использует задачи для описать такие задачи выполнения.
POST blog_index/_update_by_query?conflicts=proceed&wait_for_completion=false

GET _tasks/_qKI6E8_TDWjXyo_x-bhmw:11996

8. Другие предложения

Версии модели данных

  • Управление версиями Mapping
    • Включается в код или управляется в специальном файле, добавляет комментарии и добавляется в репозитории управления версиями, такие как Git, для удобства просмотра.
    • Добавьте поле метаданных для каждого и сохраните в нем некоторые метаданные, связанные с документом, чтобы упростить управление данными.

Запретить слишком много полей

  • Слишком большое количество полей имеет следующие недостатки:
    • Сложно поддерживать, когда есть сотни или тысячи полей, кому-то в принципе сложно четко знать значение каждого поля
    • Информация о сопоставлении хранится в состоянии кластера. Слишком большое количество полей приведет к тому, что сопоставление будет слишком большим, что в конечном итоге приведет к более медленным обновлениям.
    • Как правило, причина слишком большого количества полей связана с отсутствием качественного моделирования данных, например, с динамической установкой значения true.
    • Рассмотрите возможность разделения нескольких индексов для решения проблемы

В конце концов

Вы можете подписаться на мою общедоступную учетную запись WeChat, чтобы учиться и развиваться вместе.