Порядок ElasticSearch по длине строки

Я использую ElasticSearch через NEST С#. У меня есть большой список информации о людях

{
   firstName: 'Frank',
   lastName: 'Jones',
   City: 'New York'
}

Я хотел бы иметь возможность фильтровать и сортировать этот список элементов по фамилии, а также упорядочивать по длине, чтобы люди, у которых всего 5 символов в имени, были в начале набора результатов, а люди с 10 символами.

Итак, с некоторым псевдокодом я хотел бы сделать что-то вроде list.wildcard("j*").sort(m => lastName.length)

Я новичок в ElasticSearch, поэтому любые примеры будут очень полезны.


person mvcNewbie    schedule 21.04.2015    source источник


Ответы (1)


Вы можете выполнить сортировку с помощью на основе скрипта. сортировка.

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

PUT /test_index

POST /test_index/doc/_bulk
{"index":{"_id":1}}
{"name":"Bob"}
{"index":{"_id":2}}
{"name":"Jeff"}
{"index":{"_id":3}}
{"name":"Darlene"}
{"index":{"_id":4}}
{"name":"Jose"}

Затем я могу упорядочить результаты поиска следующим образом:

POST /test_index/_search
{
   "query": {
      "match_all": {}
   },
   "sort": {
      "_script": {
         "script": "doc['name'].value.length()",
         "type": "number",
         "order": "asc"
      }
   }
}
...
{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 4,
      "max_score": null,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "1",
            "_score": null,
            "_source": {
               "name": "Bob"
            },
            "sort": [
               3
            ]
         },
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "4",
            "_score": null,
            "_source": {
               "name": "Jose"
            },
            "sort": [
               4
            ]
         },
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": null,
            "_source": {
               "name": "Jeff"
            },
            "sort": [
               4
            ]
         },
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "3",
            "_score": null,
            "_source": {
               "name": "Darlene"
            },
            "sort": [
               7
            ]
         }
      ]
   }
}

Для фильтрации по длине я могу использовать фильтр сценариев аналогичным образом:

POST /test_index/_search
{
   "query": {
      "filtered": {
         "query": {
            "match_all": {}
         },
         "filter": {
            "script": {
               "script": "doc['name'].value.length() > 3",
               "params": {}
            }
         }
      }
   },
   "sort": {
      "_script": {
         "script": "doc['name'].value.length()",
         "type": "number",
         "order": "asc"
      }
   }
}
...
{
   "took": 3,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 3,
      "max_score": null,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "4",
            "_score": null,
            "_source": {
               "name": "Jose"
            },
            "sort": [
               4
            ]
         },
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "2",
            "_score": null,
            "_source": {
               "name": "Jeff"
            },
            "sort": [
               4
            ]
         },
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "3",
            "_score": null,
            "_source": {
               "name": "Darlene"
            },
            "sort": [
               7
            ]
         }
      ]
   }
}

Вот код, который я использовал:

http://sense.qbox.io/gist/22fef6dc5453eaaae3be5fb7609663cc77c43dab

P.S.: Если какая-либо из фамилий будет содержать пробелы, вы можете использовать "index": "not_analyzed" в этом поле.

person Sloan Ahrens    schedule 21.04.2015
comment
Допустим, он выполняет этот поиск часто, по большому количеству документов, стоит ли просто индексировать длину? - person Robin; 21.04.2015
comment
Спасибо за такой отличный отзыв. @Robin: по большей части мои данные не изменятся, поэтому индексирование длины, как мне кажется, было бы полезно. Если у вас есть какие-либо ссылки, которые вы можете указать мне, это было бы здорово. - person mvcNewbie; 21.04.2015
comment
Нажмите кнопку ввода слишком рано. Я также столкнулся с проблемой при использовании Sense, когда он выдает исключение о том, что groovy отключен. Указав groovy в качестве языка и удалив подчеркивание в _script, я попадаю на путь большего количества ошибок. Я знаю, что это тривиально, какие-либо предложения по среде для запуска вашего примера? Я попробовал ссылку, которую вы прислали на qBox, но она привела меня к пустому редактору, может быть, вы забыли сохранить код? - person mvcNewbie; 21.04.2015
comment
Я запускал это против ES 1.3.4. В версии 1.4+ вам нужно будет включить CORS для использования приложения Sense, а также динамических сценариев. Однако индексация длины, вероятно, является лучшим производственным решением. Я думаю, вам придется рассчитать длину в вашем коде. Однако не уверен, почему редактор пуст для вас; меня устраивает. Какой браузер вы используете? Видите ли вы какие-либо ошибки JavaScript в консоли? Не могли бы вы разместить их где-нибудь для меня? - person Sloan Ahrens; 22.04.2015
comment
Спасибо, Слоан, это может быть брандмауэр, за которым я стою, я попробую еще раз сегодня вечером. - person mvcNewbie; 22.04.2015
comment
Да, проблема может быть в брандмауэре. Здесь нужно сделать AJAX-запрос, чтобы получить код: 2694d39446e53877000.qbox.io/s / - person Sloan Ahrens; 22.04.2015
comment
Включение динамических сценариев было ключом, спасибо за подсказку, Слоан. Я добавил в существующий пример следующие данные: {index:{_id:5}} {name:Bob Smith} {index:{_id:6}} {name:Jeff Husenburger} {index:{_id:7}} { name:Darlene Si} {index:{_id:8}} {name:Jose Whatchamcalit}, как вы предложили, поскольку у меня есть пробелы, я также добавил параметр not_analyzed, поэтому мой запрос выглядит так: - person mvcNewbie; 22.04.2015
comment
POST /test_index/_search { запрос: { match_all: {} }, sort: { _script: { script: doc['name'].value.length(), type: number, order: asc, index: not_analyzed } } } - person mvcNewbie; 22.04.2015
comment
извините за многочисленные комментарии. Похоже, что с пробелом там все сбивается, индекс: not_analyzed, похоже, не помог, если только я не использовал его правильно. - person mvcNewbie; 22.04.2015
comment
"index": "not_analyzed" входит в ваше сопоставление, а не в ваш запрос. Вы можете установить его в самом поле или в подполе, как описано здесь: -an-exact-match" title="эластичный поиск позволяет пользователю при желании использовать точное совпадение">stackoverflow.com/questions/29614818/, но это необходимо сделать, когда вы определяете индекс (или, по крайней мере, , прежде чем индексировать документы с этим полем). - person Sloan Ahrens; 22.04.2015
comment
Спасибо Слон, получилось! - person mvcNewbie; 22.04.2015