Git Repositories

Meilleure recherche affinée même sans l'aide de la proximité géographique
[xerox-elastic-poc.git] / src / main / java / com / viseo / xerox / elastic / Main.java
1 package com.viseo.xerox.elastic;
2
3 import org.hibernate.Session;
4 import org.hibernate.Transaction;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import javax.persistence.EntityManager;
9 import java.io.BufferedReader;
10 import java.io.IOException;
11 import java.io.InputStreamReader;
12 import java.net.URISyntaxException;
13 import java.nio.charset.StandardCharsets;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Scanner;
17
18 public class Main {
19
20     private static final double VISEO_LYON_LAT = 45.760399;
21     private static final double VISEO_LYON_LON = 4.851713;
22     private final EntityManager em;
23     private final ESJsonConfig esJsonConfig;
24     private static final Logger LOG = LoggerFactory.getLogger(Main.class);
25
26     public static void main(String[] args) {
27         System.setProperty("org.jboss.logging.provider", "slf4j");
28         try {
29             final String action;
30             if (args.length > 0) {
31                 action = args[0];
32             } else {
33                 action = "";
34             }
35             new Main().run(action);
36         } catch (Exception e) {
37             LOG.error(e.getMessage(), e);
38         } finally {
39             try {
40                 EntityManagerProvider.getInstance().getEmf().close();
41             } catch (Exception e) {
42                 e.printStackTrace();
43             }
44         }
45     }
46
47     private Main() {
48         em = EntityManagerProvider.getInstance().getEm();
49         esJsonConfig = new ESJsonConfig();
50     }
51
52     private void run(String action) throws Exception {
53         switch (action) {
54             case "create":
55                 createDb();
56                 break;
57             case "index":
58                 indexDb();
59                 break;
60             case "query":
61                 queryDb();
62                 break;
63             default:
64                 help();
65         }
66     }
67
68     private void help() {
69         LOG.info("Utiliser un des paramètres suivants:");
70         LOG.info("  create");
71         LOG.info("  index");
72         LOG.info("  query");
73     }
74
75     private void createDb() throws IOException {
76         final Session session = ((Session) em.getDelegate()).getSession();
77         try (BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/insert_data.sql"), StandardCharsets.UTF_8.name()))) {
78             final int maxLines = 100;
79             final List<String> lines = new ArrayList<>(maxLines);
80             String line;
81             while ((line = br.readLine()) != null) {
82                 lines.add(line);
83                 if (lines.size() == maxLines) {
84                     execSql(session, lines);
85                     lines.clear();
86                 }
87             }
88             if (lines.size() != 0) {
89                 execSql(session, lines);
90                 lines.clear();
91             }
92         }
93         session.close();
94     }
95
96     private void execSql(Session session, List<String> lines) {
97         Transaction tx = session.beginTransaction();
98         String sql = String.join("\n", lines).replace("{", "'||CHAR(123)||'").replace("}", "'||CHAR(125)||'");
99         session.createNativeQuery(sql).executeUpdate();
100         tx.commit();
101     }
102
103     private void indexDb() throws IOException {
104         ESRequest esRequest = new ESRequest(ESJsonConfig.ES_BASE_URL);
105         dropIndex(esRequest);
106         createIndexAndAnalyzer(esRequest);
107         paramMappings(esRequest, InterrestPoint.class, MobilityPoint.class);
108         final int bulkCount = 100;
109         List<Point> points = new ArrayList<>(bulkCount);
110         for (InterrestPoint point : em.createQuery("select p from InterrestPoint p", InterrestPoint.class).getResultList()) {
111             points.add(point);
112             if (points.size() == bulkCount) {
113                 bulkIndexPoints(esRequest, points);
114                 points.clear();
115             }
116         }
117         if (points.size() != 0) {
118             bulkIndexPoints(esRequest, points);
119             points.clear();
120         }
121         for (MobilityPoint point : em.createQuery("select p from MobilityPoint p", MobilityPoint.class).getResultList()) {
122             indexPoint(esRequest, point);
123         }
124     }
125
126     private void dropIndex(ESRequest esRequest) throws IOException {
127         esRequest.dropIndex(ESJsonConfig.INDEX_NAME);
128     }
129
130     private void createIndexAndAnalyzer(ESRequest esRequest) throws IOException {
131         esRequest.createIndex(esJsonConfig.getJsonIndex(), ESJsonConfig.INDEX_NAME);
132     }
133
134     @SafeVarargs
135     private final void paramMappings(ESRequest esRequest, Class<? extends Point>... classes) throws IOException {
136         for (Class<? extends Point> aClass : classes) {
137             esRequest.paramMapping(esJsonConfig.getJsonForMapping(), ESJsonConfig.INDEX_NAME, aClass.getSimpleName());
138         }
139     }
140
141     private void indexPoint(ESRequest esRequest, Point point) throws IOException {
142         esRequest.index(esJsonConfig.getJsonForIndexing(point), ESJsonConfig.INDEX_NAME, point.getClass().getSimpleName(), point.getId());
143     }
144
145     private void bulkIndexPoints(ESRequest esRequest, List<Point> points) throws IOException {
146         final List<String[]> jsonTuples = new ArrayList<>(points.size());
147         for (Point point : points) {
148             String jsonMetadata = esJsonConfig.getJsonMetadataForIndexing(ESJsonConfig.INDEX_NAME, point.getClass().getSimpleName(), point.getId());
149             String jsonForIndexing = esJsonConfig.getJsonForIndexing(point);
150             jsonTuples.add(new String[]{jsonMetadata, jsonForIndexing});
151         }
152         esRequest.bulkIndex(jsonTuples);
153     }
154
155     /**
156      * @see <a href="https://www.elastic.co/guide/en/elasticsearch/guide/2.x/asciifolding-token-filter.html">ascii folding</a>
157      */
158     private void queryDb() throws IOException, URISyntaxException {
159         try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
160             while (true) {
161                 final double latitude = getDouble(scanner, "Latitude", VISEO_LYON_LAT);
162                 final double longitude = getDouble(scanner, "Longitude", VISEO_LYON_LON);
163                 final boolean scoreByGeo = getBoolean(scanner, "Privilégier la recherche par proximité géographique", false);
164                 final boolean useGeo = !scoreByGeo && getBoolean(scanner, "Affiner la recherche par proximité géographique", false);
165                 esJsonConfig.setSearchMode(useGeo ? SearchMode.BY_SCORE_AND_PROXIMITY : scoreByGeo ? SearchMode.BY_PROXIMITY : SearchMode.BY_SCORE);
166                 final boolean fuzziness = getBoolean(scanner, "Avec fuzziness", false);
167                 esJsonConfig.setFuzziness(fuzziness);
168                 String queryString;
169                 while (true) {
170                     System.out.print("Query : ");
171                     queryString = scanner.nextLine();
172                     if (queryString.isEmpty()) {
173                         break;
174                     }
175                     List<Point> points = queryES(queryString, latitude, longitude);
176                     getAndPrintPoints(points);
177                 }
178                 if (getBoolean(scanner, "Quitter", true)) {
179                     break;
180                 } else {
181                     System.out.println("**********");
182                 }
183             }
184         }
185     }
186
187     private boolean getBoolean(Scanner scanner, String label, boolean def) {
188         System.out.print(String.format("%s [%s] ? ", label, def ? "O/n" : "o/N"));
189         String line = scanner.nextLine().toLowerCase().replace("o", Boolean.TRUE.toString());
190         if (line.isEmpty()) {
191             return def;
192         } else {
193             return Boolean.parseBoolean(line);
194         }
195     }
196
197     private double getDouble(Scanner scanner, String label, double def) {
198         System.out.print(String.format("%s [%f] : ", label, def));
199         String line = scanner.nextLine().replace(".", ",");
200         if (line.isEmpty()) {
201             return def;
202         } else {
203             return Double.parseDouble(line);
204         }
205     }
206
207     private List<Point> queryES(String queryString, double latitude, double longitude) throws IOException, URISyntaxException {
208         String jsonRequest = esJsonConfig.getJsonQuery(queryString, latitude, longitude);
209         String jsonResult = new ESRequest(ESJsonConfig.ES_BASE_URL).find(jsonRequest, ESJsonConfig.INDEX_NAME, queryString);
210         return esJsonConfig.parseJsonResult(jsonResult);
211     }
212
213     private void getAndPrintPoints(List<Point> points) {
214         for (Point point : points) {
215             Class<? extends Point> pointClass = point.getClass();
216             double score = point.getScore();
217             Double distanceKm = point.getDistanceKm();
218             point = em.createQuery(String.format("select p from %s p where p.id = :id", pointClass.getSimpleName()), pointClass).setParameter("id", point.getId()).getSingleResult();
219             point.setScore(score);
220             point.setDistanceKm(distanceKm);
221             LOG.info(point.toString());
222         }
223     }
224 }