Статьи

Начните первый упругий поиск на Java с пружинной загрузкой и особенностями данных

В этой статье я постараюсь дать вам простое представление о том, как использовать Elastic Search в проекте Java. Поскольку Spring Boot — это самый простой и быстрый способ начать наш проект, я решил его использовать. Кроме того, мы будем активно использовать положительные отзывы Repository от любимых Spring Data.

Давайте начнем с установки Elastic Search на нашу машину и запускаем наш эластичный сервер в первый раз.

Я захожу вastic-folder \ bin и запускаюasticsearch.bat (да, я использую Windows), но не повезло. Я получаю это:

упруго-VM

«Произошла ошибка во время инициализации ВМ
Не удалось зарезервировать достаточно места для кучи объектов
Ошибка: не удалось создать виртуальную машину Java.
Ошибка: произошло фатальное исключение. Программа будет закрыта.»

Какое отличное начало!

В моей папке bin есть файл «asticsearch.in.bat ». Я установил ES_MAX_MEM = 1g на ES_MAX_MEM = 512 МБ и вуаля это исправлено.

После этого я запускаю новый сервер без проблем.

Теперь пришло время определить документ, который мы будем индексировать в упругом поиске. Предположим, у нас есть информация о фильме для индексации. Наша модель довольно проста. Фильм имеет название, рейтинг и жанр. Я выбрал «astic_sample »в качестве имени индекса, которое звучит хорошо в качестве имени базы данных, и« movie »в качестве типа, который подходит для имени таблицы, если мы думаем в терминах реляционной базы данных. Ничего особенного в модели, как вы можете видеть.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@Document(indexName = "elastic_sample", type = "movie")
public class Movie {
 
    @Id
    private String id;
 
    private String name;
 
    @Field(type = FieldType.Nested)
    private List < Genre >  genre;
 
    private Double rating;
 
    public Double getRating() {
        return rating;
    }
 
    public void setRating(Double rating) {
        this.rating = rating;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public List < Genre >  getGenre() {
        return genre;
    }
 
    public void setGenre(List < Genre >  genre) {
        this.genre = genre;
    }
 
    public String getId() {
        return id;
    }
 
    public String getName() {
        return name;
 
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String toString() {
        return "Movie{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", genre=" + genre +
                ", rating=" + rating +
                '}';
    }
}

Для тех, кому интересно, что это за жанр, вот оно. Просто POJO.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Genre {
    private String name;
 
    public Genre() {
    }
 
    public Genre(String name) {
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
 
    @Override
    public String toString() {
        return "Genre{" +
                "name='" + name + '\'' +
                '}';
    }
 
    public void setName(String name) {
        this.name = name;
    }
}

Сейчас не время создавать слой DAO, чтобы мы могли сохранять и загружать наш документ на наш сервер эластичного поиска. Наш репозиторий расширяет классический ElasticserchRepository (не знаю, почему это поиск, а не поиск). Как вы, наверное, знаете, Spring Data может запрашивать одно или несколько полей с помощью этих предопределенных методов, где мы используем имена наших полей. findByName будет искать в поле имени, findByRating будет искать в поле рейтинга и так далее. Более того, благодаря Spring Data нам не нужно писать для него реализацию, мы просто помещаем имена методов в интерфейс, и на этом все.

1
2
3
4
5
public interface MovieRepository extends ElasticsearchRepository < Movie, Long > {
    public List < Movie >  findByName(String name);
 
    public List < Movie>  findByRatingBetween(Double beginning, Double end);
}

Наш уровень DAO будет вызываться уровнем службы:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
@Service
public class MovieService {
 
    @Autowired
    private MovieRepository repository;
 
    public List < Movie >  getByName(String name) {
        return repository.findByName(name);
    }
 
    public List < Movie >  getByRatingInterval(Double beginning, Double end) {
        return repository.findByRatingBetween(beginning, end);
    }
 
    public void addMovie(Movie movie) {
        repository.save(movie);
    }
}

Вот основной класс, который мы будем использовать для запуска нашего приложения. EnableAutoConfiguration автоматически настроит все, что распознает в нашем пути к классам. ComponentScan будет сканировать аннотации Spring в главном каталоге Class.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class BootElastic implements CommandLineRunner {
 
    @Autowired
    private MovieService movieService;
 
    private static final Logger logger = LoggerFactory.getLogger(BootElastic.class);
 
// add star wars and
// princess bride as a movie
// to elastic search
    private void addSomeMovies() {
        Movie starWars = getFirstMovie();
        movieService.addMovie(starWars);
 
        Movie princessBride = getSecondMovie();
        movieService.addMovie(princessBride);
    }
 
    private Movie getSecondMovie() {
        Movie secondMovie = new Movie();
        secondMovie.setId("2");
        secondMovie.setRating(8.4d);
        secondMovie.setName("The Princess Bride");
 
        List < Genre >  princessPrideGenre = new ArrayList < Genre >();
        princessPrideGenre.add(new Genre("ACTION"));
        princessPrideGenre.add(new Genre("ROMANCE"));
        secondMovie.setGenre(princessPrideGenre);
 
        return secondMovie;
    }
 
 
    private Movie getFirstMovie() {
        Movie firstMovie = new Movie();
        firstMovie.setId("1");
        firstMovie.setRating(9.6d);
        firstMovie.setName("Star Wars");
 
        List < Genre >  starWarsGenre = new ArrayList < Genre >();
        starWarsGenre.add(new Genre("ACTION"));
        starWarsGenre.add(new Genre("SCI_FI"));
        firstMovie.setGenre(starWarsGenre);
 
        return firstMovie;
    }
 
    public void run(String... args) throws Exception {
        addSomeMovies();
        // We indexed star wars and pricess bride to our movie
        // listing in elastic search
 
        //Lets query if we have a movie with Star Wars as name
        List < Movie > starWarsNameQuery = movieService.getByName("Star Wars");
        logger.info("Content of star wars name query is {}", starWarsNameQuery);
 
        //Lets query if we have a movie with The Princess Bride as name
        List < Movie >  brideQuery = movieService.getByName("The Princess Bride");
        logger.info("Content of princess bride name query is {}", brideQuery);
 
 
        //Lets query if we have a movie with rating between 6 and 9
        List < Movie >  byRatingInterval = movieService.getByRatingInterval(6d, 9d);
        logger.info("Content of Rating Interval query is {}", byRatingInterval);
    }
 
    public static void main(String[] args) throws Exception {
        SpringApplication.run(BootElastic.class, args);
    }
}

Если мы запустим его, результат будет:

1
2
3
015-02-28 18:26:12.368  INFO 3616 --- [           main] main.BootElastic: Content of star wars name query is [Movie{id=1, name='Star Wars', genre=[Genre{name='ACTION'}, Genre{name='SCI_FI'}], rating=9.6}]
2015-02-28 18:26:12.373  INFO 3616 --- [           main] main.BootElastic: Content of princess bride name query is [Movie{id=2, name='The Princess Bride', genre=[Genre{name='ACTION'}, Genre{name='ROMANCE'}], rating=8.4}]
2015-02-28 18:26:12.384  INFO 3616 --- [           main] main.BootElastic: Content of Rating Interval query is [Movie{id=2, name='The Princess Bride', genre=[Genre{name='ACTION'}, Genre{name='ROMANCE'}], rating=8.4}]

Как видно из интервала запроса, извлекается только принцесса-невеста. Мы не сделали никакой конфигурации, верно? Это необычно. Я должен поделиться с вами огромным файлом конфигурации:

1
2
3
spring.data.elasticsearch.cluster-nodes=localhost:9300
 # if spring data repository support is enabled
spring.data.elasticsearch.repositories.enabled=true

Обычно вы используете порт 9200 при запросе к вашему эластичному серверу. Но когда мы программно достигаем его, мы используем 9300. Если у вас более одного узла, вы должны разделить их запятой и использовать 9301, 9302 и т. Д. В качестве номеров портов. Наш файл POM тоже не удивителен. Просто эластичный стартовый пом и мы готовы к работе.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    <modelversion>4.0.0</modelversion>
 
    <groupid>caught.co.nr</groupid>
    <artifactid>boot-elastic-sample</artifactid>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
 
    <!-- Inherit defaults from Spring Boot -->
    <parent>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-parent</artifactid>
        <version>1.2.2.RELEASE</version>
    </parent>
 
    <dependencies>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-data-elasticsearch</artifactid>
        </dependency>
 
    </dependencies>
 
    <!-- Needed for fat jar -->
    <build>
        <plugins>
            <plugin>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-maven-plugin</artifactid>
            </plugin>
        </plugins>
    </build>
</project>

Как вы видите, благодаря Spring Boot and Data довольно легко работать с эластичным поиском. Давайте посмотрим, что мы проиндексировали с сервера API также. Я буду использовать Sense — хромированный плагин для упругих команд.

упруго-чувственное кино поиск

Вот результат JSON:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": 1,
      "hits": [
         {
            "_index": "elastic_sample",
            "_type": "movie",
            "_id": "1",
            "_score": 1,
            "_source": {
               "id": 1,
               "name": "Star Wars",
               "genre": [
                  {
                     "name": "ACTION"
                  },
                  {
                     "name": "SCI_FI"
                  }
               ]
            }
         },
         {
            "_index": "elastic_sample",
            "_type": "movie",
            "_id": "2",
            "_score": 1,
            "_source": {
               "id": 2,
               "name": "The Princess Bride",
               "genre": [
                  {
                     "name": "ACTION"
                  },
                  {
                     "name": "ROMANCE"
                  }
               ]
            }
         }
      ]
   }
}
  • Вы можете проверить весь проект в GitHub .