Java >> Java tutorial >  >> Tag >> Spring

Hovedførst elastisk søgning på java med fjederstøvle og datafunktioner

I denne artikel vil jeg prøve at give dig en nem introduktion til, hvordan du bruger Elastic Search i et Java-projekt. Da Spring Boot er den nemmeste og hurtigste måde at starte vores projekt på, vælger jeg at bruge den. Desuden vil vi i høj grad bruge Repository goodies af elskede Spring Data.

Lad os starte med at installere Elastic Search på vores maskine og køre vores elastiske server for første gang.

Jeg går til elastic-folder\bin og kører elasticsearch.bat (ja, jeg bruger Windows), men uden held. Jeg får dette:


“Der opstod en fejl under initialisering af VM
Kunne ikke reservere nok plads til objektbunke
Fejl:Kunne ikke oprette Java Virtual Machine.
Fejl:Der er opstået en fatal undtagelse. Programmet afsluttes.”

Hvilken god start!

I min bin-mappe er der en "elasticsearch.in.bat" fil. Jeg indstillede ES_MAX_MEM=1g til ES_MAX_MEM=512mb og voila det er løst.

Jeg starter en ny server uden problemer derefter.

Nu er det tid til at definere det dokument, vi vil indeksere i elastisk søgning. Antag, at vi har filmoplysninger at indeksere. Vores model er ret ligetil. Filmen har et navn, rating og en genre. Jeg valgte "elastic_sample" som indeksnavn, der lyder godt som databasenavn og "film" som type, hvilket er godt for et tabelnavn, hvis vi tænker i relationelle databasetermer. Intet fancy i modellen, som du kan se.

@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 +
                '}';
    }
}

For dem, der spekulerer på, hvad genre er, er det her. Bare en POJO.

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;
    }
}

Det er ikke tid til at oprette DAO-lag, så vi kan gemme og indlæse vores dokument til/fra vores elastiske søgeserver. Vores repository udvider det klassiske ElasticserchRepository (ingen idé om, hvorfor det er søgning og ikke søgning). Som du sikkert ved, kan Spring Data forespørge på et eller flere felter med disse foruddefinerede metoder, hvor vi bruger vores feltnavne. findByName vil søge i navnefeltet, findByRating vil søge i vurderingsfeltet osv. så videre. Takket være Spring Data behøver vi desuden ikke skrive implementering til det, vi sætter blot metodenavne i grænsefladen, og det er færdigt.

public interface MovieRepository extends ElasticsearchRepository < Movie, Long > {
    public List < Movie >  findByName(String name);

    public List < Movie>  findByRatingBetween(Double beginning, Double end);
}

Vores DAO-lag kaldes af et servicelag:

@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);
    }
}

Her er hovedklassen, vi vil bruge til at køre vores applikation. EnableAutoConfiguration vil automatisk konfigurere alt, hvad det genkender under vores klassesti. ComponentScan scanner for forårsannoteringer under hovedbiblioteket for klassen.

@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);
    }
}

Hvis vi kører det, er resultatet:

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}]

Som du kan se, hentede intervalforespørgslen kun Princess Bride. Vi har ikke lavet nogen konfiguration vel? Det er usædvanligt. Jeg er nødt til at dele den enorme konfigurationsfil med dig:

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

Normalt ville du bruge port 9200, når du forespørger på din elastiske server. Men når vi programmæssigt når det, bruger vi 9300. Hvis du har mere end én node, vil du adskille dem med et komma og bruge 9301, 9302 osv. som portnumre. Vores pom-fil er heller ingen overraskelse. Bare en elastisk startpom, så er vi klar.

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemalocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <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>

Som du kan se takket være Spring Boot og Data er det ret nemt at arbejde med elastisk søgning. Lad os også tjekke, hvad vi indekserede fra server-api'en. Jeg vil bruge Sense -et krom plug-in til elastiske kommandoer-.

Her er resultatet json:

{
   "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"
                  }
               ]
            }
         }
      ]
   }
}
  • Du kan tjekke hele projektet i github.

Java tag