Suggest API и Spark


(Evgeny Lazarev) #1

Для целей автозаполнения хочу применить Suggest API (конфигурировал исходя из статьи).

Сейчас встал вопрос, как это дело подружить с загрузкой данных Sparkом.
Код загрузки элементарен:

JavaRDD<Map<String, Object>> resultRdd = inputRdd.map(line -> {
if (line.trim().isEmpty()) {
return null;
}
String[] arr = line.split("\t");
ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("unchecked")
Map<String, Object> map = mapper.readValue(arr[1], Map.class);
map.put(esMappingId, arr[0]);
return map;
}).filter(x -> x != null);

Проблема в том, что я не пойму, как можно передать данные (пробую на примере простого числового айди) в поле с suggest типом.

Если просто добавляю в мапу map.put("SUGGEST_ID", arr[0]); , маппинг у индекса меняется (создается отдельный тип и ко всему содержимому добавляется обычное поле SUGGEST_ID).

Если добавляю SUGGEST_ID в виде мапы с input-полем и айди внутри (

Map<String, String> map2 = new HashMap<>();
map2.put("input", arr[0]);
map.put("SUGGEST_ID", map2);

)
происходит тоже самое - создается новый тип.

Создаю индекс в таком виде:

{
  "test_2": {
    "aliases": {},
    "mappings": {
      "doc": {
        "properties": {
          "ID": {
            "type": "string"
          },
          "suggest_ID": {
            "search_analyzer": "simple",
            "type": "completion",
            "payloads": "false",
            "analyzer": "simple"
          },
          "test-id": {
            "type": "string"
          }
        }
      }
    },
    "settings": {
      "index": {
        "number_of_shards": "5",
        "number_of_replicas": "1"
      }
    },
    "warmers": {}
  }
}

а после спарка имею что то следующее:

{
  "test_2": {
    "aliases": {},
    "mappings": {
      "doc": {
        "properties": {
          "ID": {
            "type": "string"
          }, 
          "suggest_ID": {
            "properties": {
              "completion": {
                "properties": {
                  "field": {
                    "type": "string"
                  },
                  "size": {
                    "type": "long"
                  }
                }
              },
              "input": {
                "type": "string"
              },
              "text": {
                "type": "string"
              }
            }
          } 
        }
      }
    },
    "settings": {
      "index": {
        "test_2": {
          "settings": {
            "index": {
              "number_of_shards": "5",
              "number_of_replicas": "1"
            }
          },
          "mappings": {
            "doc": {
              "properties": {

                "suggest_ID": {
                  "search_analyzer": "simple",
                  "type": "completion",
                  "payloads": "false",
                  "analyzer": "simple"
                } ,
                "ID": {
                  "type": "string"
                }
              }
            }
          }
        },
        "creation_date": "1465489137103",
        "number_of_shards": "5",
        "number_of_replicas": "1",
        "uuid": "zD-HR3pgRsK0Mvyj4IIuuA",
        "version": {
          "created": "2030299"
        }
      }
    },
    "warmers": {}
  }
}

Вопрос - как можно загрузить данные также и в suggest-поле?
Или же оставить эту затею и воспользоваться советом того же товарища из ответа


(Igor Motov) #2

Проблема в том, как вы создаете индекс. Похоже, что вы и установки и маппинг засунули в установки каким-то образом


  "test_2": {
    "aliases": {},
    "mappings": {
      "doc": {
.... поля добавленные elasticsearch динамически ....
      }
    },
    "settings": {
      "index": {
       // ваши установки должны появится тут без имени индекса 
        "test_2": {
         // все внутри "test_2": {...} игнорируется потому что elasticsearch понятия не имеет
         // что такое index.test_2.settings.index.number_of_shards, например
          "settings": {
            "index": {
              "number_of_shards": "5",
              "number_of_replicas": "1"
            }
          },
          // этот меппинг тоже игнорируется, потому что elasticsearch рассматривает его, как
          // неизвестный параметр установок
          "mappings": {
            "doc": {
              "properties": {

(Evgeny Lazarev) #3

Спасибо, разобрался.

Мало того, что неправильный JSON был, так ещё и в head его неправильно запихивал...


(Evgeny Lazarev) #4

Да, кстати, возник вопрос - а можно ли использовать suggest для численных данных?


(Igor Motov) #5

а можно ли использовать suggest для численных данных?

Как вы себе это представляете? Не могли бы вы привести пример?


(Evgeny Lazarev) #6

Ну, например, поиск Java-вского BigInteger-а..


(Igor Motov) #7

Ну, например, поиск Java-вского BigInteger-а..

То есть, я набираю 123, и elasticsearch предлагет 123456789012334, 1234, 1234555? Так как-то?


(Evgeny Lazarev) #8

Примерно.. На самом деле мне интересны большие числа, по 10-15 знаков.


(Igor Motov) #9

Примерно.. На самом деле мне интересны большие числа, по 10-15 знаков.

Я вот что пытаюсь понять, Вам эти числа интересны именно как числа с точки зрения suggest, или они по функциональности просто слова с 10-15 символами, в которых все символы, по какой-то причине, являются цифрами.


(Evgeny Lazarev) #10

Да, они интересны именно как слова.

При этом тип самой колонки я явно указываю как string


(Igor Motov) #11

Для suggest все равно из каких знаков ваши слова состоят. Так что можно использовать точно так же, как и для слов.


(Evgeny Lazarev) #12

Нашел причину всех своих бед.

Оказалось, что если необходимо использовать suggest для чисел, то нужно менять анализатор.
simple для этих целей не подходит. В доках lucene об этом прямо так и сказано:

/** An {@link Analyzer} that filters {@link LetterTokenizer} 
 *  with {@link LowerCaseFilter} 
 **/
public final class SimpleAnalyzer extends Analyzer {

Поменял анализатор на whitespace и получил желаемое поведение. Более правильного анализатора не нашел (ну, точнее нашел NumericIntegerAnalyzer, но не нашел его имени для указания в jsonе при создании).


(Igor Motov) #13

Да, simple просто все не-буквы выкидывает. У Вас цифры эти пробелами разделены или просто в тексте случайным образом упоминаются? Если второе, то лучше воспользоваться standard, он кроме разделения по пробелам еще и знаки препинания правильно обрабатывает.


(Evgeny Lazarev) #14

У меня и первое, и второе есть. Так что буду смотреть и тестировать.

Спасибо большое за подсказки.


(system) #15