1 Elasticsearch與Solr區別
在Java的全文檢索裏面有solr
和elasticsearch
兩大高級玩意
首先我們來看看他們的區別:
1)Solr建立索引時候,搜索效率下降,實時搜索效率不高,es實時搜索效率高
2)Solr利用Zookeeper進行分佈式管理,而Elasticsearch自身帶有分佈式協調管理功能。
3)Solr支持更多格式的數據,比如JSON、XML、CSV,而Elasticsearch僅支持json文件格式。
4)Solr官方提供的功能更多,而Elasticsearch本身更注重於核心功能,高級功能多有第三方插件提供
5)Solr在傳統的搜索應用中表現好於Elasticsearch,但在處理實時搜索應用時效率明顯低於Elasticsearch。
6)Solr是傳統搜索應用的有力解決方案,但Elasticsearch更適用於新興的實時搜索應用
。
因此我們選擇Elasticsearch
2 elasticsearch的安裝
2.1 創建用戶
因爲elasticsearch出於系統安全考慮,不能使用root啓動.所以要建立其他的普通用戶.
創建用戶dev,密碼:123456
[root@dev-2 ~]# useradd dev
[root@dev-2 ~]# passwd dev
Changing password for user dev.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@dev-2 ~]# id dev
2.2 下載elasticsearch且配置環境變量
下載:
[root@dev-2 elasticsearch]# wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-
6.3.0.tar.gz
--2018-09-05 11:32:45-- https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.3.0.tar.gz
Resolving artifacts.elastic.co (artifacts.elastic.co)... 107.21.253.15, 184.72.242.47, 107.21.237.95,
...
Connecting to artifacts.elastic.co (artifacts.elastic.co)|107.21.253.15|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 91423553 (87M) [application/x-gzip]
Saving to: ‘elasticsearch-6.3.0.tar.gz’
100%
[=======================================================================================================
==============================================>] 91,423,553 947KB/s in 1m 55s
2018-09-05 11:34:31 (776 KB/s) - ‘elasticsearch-6.3.0.tar.gz’ saved [91423553/91423553]
[root@dev-2 elasticsearch]#
解壓
[root@dev-2 elasticsearch]# tar -xvf elasticsearch-6.3.0.tar.gz
配置環境變量
[root@dev-2 elasticsearch-6.3.0]# vim /etc/profile
# import elasticsearch
export SEARCH_HOME='/opt/soft/elasticsearch/elasticsearch-6.3.0'
export PATH=$PATH:$SEARCH_HOME/bin
[root@dev-2 elasticsearch-6.3.0]# source /etc/profile
設置所有者爲dev
[root@dev-2 elasticsearch]# ll
total 89284
drwxr-xr-x. 8 root root 143 Sep 05 11:43 elasticsearch-6.3.0
[root@dev-2 elasticsearch]# chown -R dev:dev elasticsearch-6.3.0
[root@dev-2 elasticsearch]# ll
total 89284
drwxr-xr-x. 8 dev dev 143 Sep 05 11:43 elasticsearch-6.3.0
[root@dev-2 elasticsearch]
2.3elasticsearch的配置
修改JVM參數
-Xms和-Xmx的值要一致.
[root@dev-2 elasticsearch-6.3.0]# cd config/
[root@dev-2 config]# ls
elasticsearch.yml jvm.options log4j2.properties role_mapping.yml roles.yml users users_roles
[root@dev-2 config]# vim jvm.options
# Xms represents the initial size of total heap space
# Xmx represents the maximum size of total heap space
-Xms1g
-Xmx1g
[root@dev-2 config]#
修改啓動參數
[root@dev-2 config]# vim elasticsearch.yml
# Set the bind address to a specific IP (IPv4 or IPv6):
#使用 雲服務器時用以下地址;若爲本地服務器時則使用本地服務器地址;
network.host: 0.0.0.0
#
# Set a custom port for HTTP:
#
http.port: 9200
#
# 開啓跨域訪問支持,默認爲false
#
http.cors.enabled: true
#
# 跨域訪問允許的域名地址,(允許所有域名)以上使用正則
#
http.cors.allow-origin: /.*/
[root@dev-2 config]#
3 啓動Elasticsearch
切換到dev啓動
[root@dev-2 elasticsearch-6.3.0]# su dev
[dev@dev-2 elasticsearch-6.3.0]$ elasticsearch
[2018-09-05T11:50:22,771][INFO ][o.e.n.Node ] [] initializing ...
但啓動報錯,如下
[2018-09-05T11:50:40,429][INFO ][o.e.b.BootstrapChecks ] [eme3ye6] bound or publishing to a nonloopback address, enforcing bootstrap checks
ERROR: [4] bootstrap checks failed
[1]: initial heap size [268435456] not equal to maximum heap size [536870912]; this can cause resize
pauses and prevents mlockall from locking the entire heap
[2]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
[3]: max number of threads [3852] for user [dev] is too low, increase to at least [4096]
[4]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
[2018-09-05T11:50:40,506][INFO ][o.e.n.Node ] [eme3ye6] stopping ...
[2018-09-05T11:50:40,606][INFO ][o.e.n.Node ] [eme3ye6] stopped
[2018-09-05T11:50:40,606][INFO ][o.e.n.Node ] [eme3ye6] closing ...
[2018-09-05T11:50:40,619][INFO ][o.e.n.Node ] [eme3ye6] closed
請切換到root,修改 /etc/security/limits.conf
文件
[root@dev-2 elasticsearch-6.3.0]# vim /etc/security/limits.conf
#@student - maxlogins 4
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
# End of file
[root@dev-2 elasticsearch-6.3.0]#
修改/etc/sysctl.conf
文件
[root@dev-2 etc]# vim /etc/sysctl.conf
vm.max_map_count=655360
[root@dev-2 etc]# sysctl -p
vm.max_map_count = 655360
再切換到dev
用戶啓動elasticsearch
[dev@dev-2 elasticsearch-6.3.0]$ nohup elasticsearch &
[dev@dev-2 elasticsearch-6.3.0]$ cat nohup.out
....
[2018-09-05T12:15:27,438][INFO ][o.e.x.s.t.n.SecurityNetty4HttpServerTransport] [eme3ye6]
publish_address {47.98.143.72:9200}, bound_addresses {47.98.143.72:9200}
[2018-09-05T12:15:27,438][INFO ][o.e.n.Node ] [eme3ye6] started
[2018-09-05T12:15:27,949][WARN ][o.e.x.s.a.s.m.NativeRoleMappingStore] [eme3ye6] Failed to clear cache
for realms [[]]
[2018-07-04T10:17:37,982][INFO ][o.e.l.LicenseService ] [eme3ye6] license [36a89374-568c-4f0d-83ce-
37475ca3015c] mode [basic] - valid
[2018-07-04T10:17:37,996][INFO ][o.e.g.GatewayService ] [eme3ye6] recovered [0] indices into
cluster_state
....
[dev@dev-2 elasticsearch-6.3.0]$ jps
21874 Jps
4969 Elasticsearch
[dev@dev-2 elasticsearch-6.3.0]# netstat -lnp|grep 9200
tcp 0 0 0.0.0.0:9200 0.0.0.0:* LISTEN 4969/java
[dev@dev-2 elasticsearch-6.3.0]# curl 47.98.143.72:9200
{
"name" : "jDY6CwJ",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "LhuAiJqpRVqKOxIUZ0Xa3Q",
"version" : {
"number" : "6.3.0",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "424e937",
"build_date" : "2018-06-11T23:38:03.357887Z",
"build_snapshot" : false,
"lucene_version" : "7.3.1",
"minimum_wire_compatibility_version" : "5.6.0",
"minimum_index_compatibility_version" : "5.0.0"
},
"tagline" : "You Know, for Search"
}
4 中文分詞
4.1 安裝IK分詞器
**Github下載和Elasticsearch相同版本的IK分詞器: **
IK分詞器下載地址
在 plugins/
文件夾下建立ik
文件夾,並把壓縮包內容解壓到 ik 文件夾.
[root@dev-2 plugins]# pwd
/opt/soft/elasticsearch/elasticsearch-6.3.0/plugins
[dev@dev-2 plugins]$ mkdir ik
[dev@dev-2 plugins]$ cd ik
[dev@dev-2 ik]$ unzip elasticsearch-analysis-ik-6.3.0.zip -d .
[dev@dev-2 ik]$ ls
commons-codec-1.9.jar config httpclient-4.5.2.jar plugindescriptor.properties
commons-logging-1.2.jar elasticsearch-analysis-ik-6.3.0.jar httpcore-4.4.4.jar
重新啓動ElasticSear
[dev@dev-2 elasticsearch-6.3.0]$ nohup bin/elasticsearch &
[1] 17149
[dev@dev-2 elasticsearch-6.3.0]$ jps
17236 Jps
17149 Elasticsearch
[dev@dev-2 elasticsearch-6.3.0]$ cat nohup.out |grep ik
[2018-09-05T13:42:57,317][INFO ][o.e.p.PluginsService ] [eme3ye6] loaded plugin [analysis-ik]
[2018-09-05T13:43:21,229][INFO ][o.w.a.d.Monitor ] try load config from
/opt/soft/elasticsearch/elasticsearch-6.3.0/config/analysis-ik/IKAnalyzer.cfg.xml
[2018-09-05T13:43:49,372][INFO ][o.w.a.d.Monitor ] try load config from
/opt/soft/elasticsearch/elasticsearch-
6.3.0/plugins/ik/config/https://blog.csdn.net/z90818/article/details/78644293.cfg.xml
[dev@dev-2 elasticsearch-6.3.0]$
4.2 具體使用
Q: 如何使用IK分詞器對自己需要存放的數據進行分詞和查詢?
A: 在創建index和type的時候,就指定type裏面的字段是否需要分詞.就像我們在mysql數據庫先搭建表結構一樣
例如: 指定Index爲 testindex,type爲 testtype裏面的字段 name使用 ik_max_word 分詞存儲和搜索.
curl -XPOST http://localhost:9200/testindex/testtype/_mapping -H 'Content-Type:application/json' -d'
{
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
}'
詳細例子可見: ik-github例子
5 應用
5.1 簡單的搜索引擎(實現對電影節目的全文檢索)
5.1.1概述
注:該系統所用的數據由於數據量較大,則由本人事先從數據庫讀取數據存到ElasticSearch,下面會做詳細描述以便後期檢索需要
該檢索系統使用Spring Boot結合Jest +mysql快速實現對阿里雲ElasticSearch的全文檢索功能。
主要使用組件:
Jest:一種rest訪問es的客戶端
elasticsearch:實現全文檢索
thymeleaf:web前端模版框架
5.1.2 項目目錄結構
5.1.3 maven配置及yml配置文件
a) maven配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>cheng.demo.springcloud</groupId>
<artifactId>jest-elasticsearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>jest-elasticsearch</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>io.searchbox</groupId>
<artifactId>jest</artifactId>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
<version>1.0</version>
</dependency>
<!-- 添加mybatis支持 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.2.0</version>
</dependency>
<!--Mapper插件 -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.3.9</version>
</dependency>
<!-- generator -->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
</dependency>
<!-- 添加mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--添加spring JDBC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.11</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- 前端框架模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
b) yml配置文件
server:
port: 7081
spring:
elasticsearch:
jest:
uris:
- http://47.98.143.72:9200
read-timeout: 5000
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://10.10.2.233:3306/irs_cms
username: root
password: xxxxxx
thymeleaf:
cache: false
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.cheng.elasticsearch.entity
5.1.4 Entity實體類BusVod(電影資源)
@Document(indexName = BusVod.INDEX, type = BusVod.ORDER_TYPE, shards = 6, replicas = 2, refreshInterval = "-1")
public class BusVod implements Serializable{
private static final long serialVersionUID = -763638353551774166L;
//建立索引
public static final String INDEX = "movie-test";
//類型
public static final String ORDER_TYPE = "movie-type";
private String name;
private String director;
private String actor;
private String releaseTime;
private String provider;
private String vodDesc;
private String screenWriter;
// 電影描述,可以通過ik 分詞器進行分詞
@Field(type = FieldType.String, searchAnalyzer = "ik", analyzer = "ik")
private String summaryLong;
public BusVod(String name, String director, String actor, String releaseTime, String provider, String vodDesc, String screenWriter, String summaryLong) {
//省略
}
public BusVod() {
}
//getter setter 省略...
}
5.1.5 mapper資源(從數據庫取所有的電影資源數據)
a) java類(BusVodMapper.java)
@Repository
public interface BusVodMapper extends Mapper<BusVod> {
//從數據庫查詢所有的電影資源數據
List<BusVod> findList();
}
b) mybatis-xml文件(BusVodMapper.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.cheng.elasticsearch.mapper.BusVodMapper">
<resultMap id="resMap" type="com.cheng.elasticsearch.entity.BusVod">
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="director" property="director" jdbcType="VARCHAR" />
<result column="actor" property="actor" jdbcType="VARCHAR" />
<result column="release_time" property="releaseTime" jdbcType="VARCHAR" />
<result column="provider" property="provider" jdbcType="VARCHAR" />
<result column="vod_desc" property="vodDesc" jdbcType="VARCHAR" />
<result column="screen_writer" property="screenWriter" jdbcType="VARCHAR"/>
<result column="summary_long" property="summaryLong" jdbcType="VARCHAR"/>
</resultMap>
<sql id="column">
bus_vod.name name,
bus_vod.director director,
bus_vod.actor actor,
bus_vod.release_time release_time,
bus_vod.provider provider,
bus_vod.vod_desc vod_desc,
bus_vod.screen_writer screen_writer,
bus_vod.summary_long summary_long
</sql>
<select id="findList" resultMap="resMap">
select
<include refid="column"></include>
from bus_vod
</select>
</mapper>
5.1.6 Service配置
a) 接口
public interface BusVodService {
//從數據庫導入數據到elasticsearch
List<BusVod> findList();
void saveBusvod(List<BusVod> busVodList);
//根據輸入的值搜索複合的內容
List<BusVod> searchEntity(String keyword);
}
b) 實現類
@Service
public class BusVodServiceImpl implements BusVodService {
private static final Logger LOGGER = LoggerFactory.getLogger(BusVodServiceImpl.class);
@Autowired
private JestClient jestClient;
@Autowired
private BusVodMapper mapper;
@Override
public List<BusVod> findList() {
List<BusVod> busVods = mapper.findList();
return busVods;
}
/**
* 批量保存內容到ES
*/
@Override
public void saveBusvod(List<BusVod> busVodList) {
Bulk.Builder bulk = new Bulk.Builder();
for(BusVod busVod : busVodList) {
Index index = new Index.Builder(busVod).index(BusVod.INDEX).type(BusVod.ORDER_TYPE).build();
bulk.addAction(index);
}
try {
jestClient.execute(bulk.build());
LOGGER.info("ES 插入完成");
} catch (IOException e) {
e.printStackTrace();
LOGGER.error(e.getMessage());
}
}
/**
* 通過一個關鍵字搜索對應的電影資源
* @param keyword
* @return
*/
@Override
public List<BusVod> searchEntity(String keyword) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
if (keyword != null) {
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("actor",keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("director", keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("name", keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("provider", keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("releaseTime", keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("screenWriter", keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("summaryLong", keyword));
boolQueryBuilder.should(QueryBuilders.commonTermsQuery("vodDesc", keyword));
}
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("summaryLong");//高亮summaryLong
highlightBuilder.field("name");
highlightBuilder.preTags("<font color='red'>").postTags("</font>");//高亮標籤
highlightBuilder.fragmentSize(500);//高亮內容長度
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.highlight(highlightBuilder);
searchSourceBuilder.query(boolQueryBuilder).size(10); //需要檢索的數據條數,這裏可以設計爲分頁
Search search = new Search.Builder(searchSourceBuilder.toString())
.addIndex(BusVod.INDEX).addType(BusVod.ORDER_TYPE).build();
try {
SearchResult result = jestClient.execute(search);
System.out.println("本次查詢共查到:"+result.getTotal()+"部電影!");
List<SearchResult.Hit<BusVod,Void>> hits = result.getHits(BusVod.class);
System.out.println(hits.size());
List<BusVod> busVodlists = new ArrayList<BusVod>();
for (SearchResult.Hit<BusVod, Void> hit : hits) {
BusVod source = hit.source;
//獲取高亮後的內容
Map<String, List<String>> highlight = hit.highlight;
if (highlight!=null){
List<String> summaryLong = highlight.get("summaryLong");//高亮後的summaryLong
if(summaryLong!=null){
source.setSummaryLong(summaryLong.get(0));
}
List<String> name = highlight.get("name");//高亮後的name
if(name!=null){
source.setName(name.get(0));
}
}
BusVod busVod = new BusVod();
busVod.setName(source.getName());
busVod.setSummaryLong(source.getSummaryLong());
busVod.setActor(source.getActor());
busVod.setDirector(source.getDirector());
busVod.setScreenWriter(source.getScreenWriter());
busVod.setVodDesc(source.getVodDesc());
busVod.setReleaseTime(source.getReleaseTime());
busVod.setProvider(source.getProvider());
busVodlists.add(busVod);
}
return busVodlists;
} catch (IOException e) {
LOGGER.error(e.getMessage());
e.printStackTrace();
}
return null;
}
}
5.1.7 Controller類
調用Service接口,數據返回到頁面(VodController)
@Controller
@RequestMapping("/bus/vod")
public class VodController {
@Autowired
private BusVodService busVodService;
//利用fiddler工具或者postman工具調用該方法可實現數據庫數據導入到elasticsearch中
@RequestMapping("/list")
public String getList(HttpServletRequest request) {
List<BusVod> busVods = busVodService.findList();
List<BusVod> addList = new ArrayList<BusVod>();
for(BusVod busVod : busVods){
BusVod newEntity = new BusVod(busVod.getName(),busVod.getDirector(),busVod.getActor(),
busVod.getReleaseTime(), busVod.getProvider(),busVod.getVodDesc(), busVod.getScreenWriter(), busVod.getSummaryLong());
addList.add(newEntity);
}
busVodService.saveBusvod(addList);
return "";
}
//實現全文檢索功能
@RequestMapping(value = "/query", method = RequestMethod.GET)
public String query(@RequestParam(name = "keyword", required = false) String keyword,
ModelMap map ) {
List<BusVod> busVodList= busVodService.searchEntity(keyword);
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
map.addAttribute("movieLists",busVodList);
return "moviesList";
}
}
5.1.8 前端頁面實現
前端頁面使用的是thymeleaf模板(moviesList.html)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>電影資源檢索</title>
<link rel='stylesheet' href='/webjars/bootstrap/css/bootstrap.min.css'/>
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body style="width: 1000px; margin-left: 200px;">
<form action="/bus/vod/query" class="px-5 py-3" >
<div class="input-group">
<input name="keyword" type="text" class="form-control" placeholder="請輸入搜索內容" aria-label="請輸入搜索內容" aria-describedby="basic-addon2"/>
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="submit">搜索</button>
</div>
</div>
</form>
<ul class="list-group">
<li th:each="movie : ${movieLists}" class="list-group-item">
<div class="row">
<!-- 這裏可添加url鏈接,還未實現 -->
<a th:href="${movie.getName()}">
<h4 scope="row" th:utext="${movie.name}" ></h4>
</a>
<h6 scope="row" th:text="${movie.getActor()}" class="align-bottom" ></h6>
</div>
<div class="row">
<h6 scope="row" th:utext="${movie.summaryLong}"/>
</div>
</li>
<hr/>
</ul>
</body>
</html>