In my database contain about 2 millions rows. That contains collection of sentences in each rows(Not English language).
![Image of database][1]
As a example if user give 'abcd' ,that matched with both row 1,3. Therefor both should select.
Because of that huge time taken to data retrieve. I'm using following code to retrieve data. If any given word match with the database those rows should be select.
sb.append("SELECT Sentence FROM corpus Where ");
for(int k=0;k<wordList.size();k++){
sb.append( " Sentence like '%" + wordList.get(k) + "%' OR ");
}
sb.append(" 1=0");
rs2 = dbc.sqlExecute(sb.toString());
That selection word may be anywhere in the row. That may be front or middle or end. My problem is when user give some word phrase, huge time taken to select matched rows. Is there any proper way to speed my database retrieves? I think indexing may not work because of I'm not searching only the starting point of the rows. That matched words may contain anywhere in the rows. What is the efficient way to do this? Huge time taken to retrieve. Huge problem to me.Can anyone know proper way to do this?
You don't need for loop, just do like this:
sb.append("SELECT Sentence FROM corpus Where Sentence like '%");
sb.append(wordList);
sb.append("%'");
I believe the efficient solution is to use a PreparedStatement with a bind parameter and execute it in a loop. You could use a For-Each Loop, and for each word in wordList bind the parameter and then get a ResultSet (using a try-with-resources) and add the returned sentences to your List with something like
List<String> sentences = new ArrayList<>();
String sql = "SELECT Sentence FROM corpus WHERE Sentence LIKE ?";
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
for (String word : wordList) {
ps.setString(1, String.format("%%%s%%", word));
try (ResultSet rs = ps.executeQuery()) {
sentences.add(rs.getString(1));
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
While a FULLTEXT index on the Sentence column is probably advisable, this method has the benefit using the query cache and reducing the size of your query. The OR clauses just muddy the situation, since you want the matching rows of any of them. You might also consider a Set<String> sentences.
Related
I want to use autocomplete in inputTextArea. I am doing it using values from the database. I have words, digits, symbols(like #) stored in the database.
The problem is when I try typing in the textArea, the whole list of things appears. Instead, I just want only those options to come which matches the input written in the textArea, kind of autocomplete feature but it fetches values from a database.
Given below is the java code that I have written so far.
public class DbConnect {
public List<String> completeArea(String query1) {
ResultSet rs;
Statement st;
Connection con;
PreparedStatement pst;
List<String> result = new ArrayList<String>();
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost/company", "root", "");
try {
query1 = "select name from labels";
pst = con.prepareStatement(query1);
rs = pst.executeQuery();
while (rs.next()) {
result.add(rs.getString("name"));
}
} catch (Exception ex) {
System.out.println(ex);
}
} catch (Exception ex) {
System.out.println("error occured" + ex);
}
System.out.println("size is " + result.size());
return result;
}
I do not want to specify any particular letter for searching in the database, it should pick automatically when the user types in. Any help would do good. Thanks a lot.
In your example the query1 parameter of the completeArea method is the user input but you overwriting it with your query. Try with
public List<String> completeArea(String input) {
...
String query = "select name from labels where name like ?";
pst = con.prepareStatement(query);
pst.setString(1, input + "%");
...
}
Edited according to #Slaw comment. Thanks for the correction. :)
I would use <p:autoComplete /> instead of inputTextArea for this usecase.
You can find a good tutorial in the official PrimeFaces site.
Your query is
select name from labels
that will give all labels's name...
I do not want to specify any particular letter for searching in the database, it should pick automatically when the user types in. Any help would do good.
If you want some matching you must specify a condition
First of all I apologize for my grammar as english is not my first language, this is my second question for this day and its quite embarrassing already.
I just want to ask as to how I can add a search functionality to my application, like searching for keywords with filtering?
I am able to do minor search functionality like typing words on the search bar and the results will reflect on the table.
What I do want to know though is how to do something like this..
Say, if I input the word "bronte" and the word "beautiful" and the subject English is selected from the combobox, when i press GO, the result reflected in the tableview should be "of mice and men" and "wuthering heights"
How should i organize my table in the database? as i think the column 'keywords' should not be put this way. I'm out of solutions.
my code as of writing (But really farfetched from what i need):
pupulating tableview using this sample code:
public void loadDatabaseData(){
String query = "select * from table_sample";
try {
preparedStatement = connection.prepareStatement(query);
rs = preparedStatement.executeQuery();
while(rs.next()){
data.add(new table(
rs.getString("Name"),
rs.getString("Username"),
rs.getString("Password"),
rs.getString("kiki")
));
table.setItems(data);
}
preparedStatement.close();
rs.close();
}
catch(Exception e){
System.err.println(e);
}
}
Search functionality code:
#FXML
public void searchUser()
{
searchBox.textProperty().addListener((observableValue,oldValue,newValue)->{
filteredData.setPredicate((Predicate<? super table>)user->{
if(newValue==null||newValue.isEmpty()){
return true;
}
String lowerCaseFilter=newValue.toLowerCase();
if(user.getName().toLowerCase().contains(lowerCaseFilter)){
return true;
}
else if(user.getUsername().toLowerCase().contains(lowerCaseFilter)){
return true;
}
return false;
});
});
SortedList<table> sortedData=new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sortedData);
}
I am using primefaces autocomplete component with pojos and which is filled from a database table with huge number of rows.
When I select value from database which contains millions of entries (SELECT synonym FROM synonyms WHERE synonym like '%:query%') it takes a very long time to find the word on autocomplete because of huge database entries on my table and it will be bigger in future.
Is there any suggestions on making autocomplete acting fast.
Limiting the number of rows is a great way to speed-up autocomplete. I'm not clear on why you'd limit to 1000 rows though: you can't show 1000 entries in a dropdown; shouldn't you be limiting to maybe 10 entries?
Based on your comments below, here is an example database query that you should be able to adapt to your situation:
String queryString = "select distinct b.title from Books b where b.title like ':userValue'";
Query query = entityManager.createQuery(queryString);
query.setParameter("userValue", userValue + "%");
query.setMaxResults(20);
List<String> results = query.getResultList();
I finally went to using an index solar for doing fast requests while my table will contains more than 4 million entries which must be parsed fastly and without consuming a lot of memory.
Here's I my solution maybe someone will have same problem as me.
public List<Synonym> completeSynonym(String query) {
List<Synonym> filteredSynonyms = new ArrayList<Synonym>();
// ResultSet result;
// SolrQuery solrQ=new SolrQuery();
String sUrl = "http://......solr/synonym_core";
SolrServer solr = new HttpSolrServer(sUrl);
ModifiableSolrParams parameters = new ModifiableSolrParams();
parameters.set("q", "*:*"); // query everything
parameters.set("fl", "id,synonym");// send back just the id
//and synonym values
parameters.set("wt", "json");// this in json format
parameters.set("fq", "synonym:\"" + query+"\"~0"); //my conditions
QueryResponse response;
try {
if (query.length() > 1) {
response = solr.query(parameters);
SolrDocumentList dl = response.getResults();
for (int i = 0; i < dl.size(); i++) {
Synonym s = new Synonym();
s.setSynonym_id((int) dl.get(i).getFieldValue("id"));
s.setSynonymName(dl.get(i).getFieldValue("synonym")
.toString());
filteredSynonyms.add(s);
}
}
} catch (SolrServerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return filteredSynonyms;
}
Let's say I have a program that puts email addresses into a database where the email attribute is a primary key.
If I have a duplicate email address, I could deal with it in two ways.
1) run a "select email from table" query. If the email is currently in there, don't add it.
2) don't check if email is in the table. catch(SQLException e), but don't print the stack trace, simply skip over it. This way, if I'm inserting a duplicate it effectively ignores it.
Granted with method 1, I'm only executing a simple select query (no joins or anything fancy) so performance isn't really a huge issue. But if I wanted to optimize performance, would method 2 be a viable, safe way of doing this?
So instead of running a "select ..." every time, I just add it.
Are there any safety issues with skipping over the exception?
Java Example (with JDBC):
try {
String sql = "insert into emails values(?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, email);
pstmt.execute();
return true;
}
catch(SQLException e) {
// e.printStackTrace(); // skip; don't print out error
return false;
}
I have the following work on my application, in which I am trying to update the value total on my mysql database table called "porcobrar2012". However, the only value that gets updated is the last one generated in the while loop. Why? all values are been printout on the screen with no problem, but those values are not getting updated in the database.
Here is the code:
BigDecimal total = new BigDecimal("0");
try
{
//Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//Connection connection=DriverManager.getConnection("jdbc:odbc:db1","","");
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost/etoolsco_VecinetSM?user=etoolsco&password=g7Xm2heD41");
Statement statement=connection.createStatement();
String query;
query="SELECT * FROM porcobrar2012";
ResultSet resultSet=statement.executeQuery(query);
while(resultSet.next())
{
out.println(resultSet.getString(2)+"");out.println(resultSet.getBigDecimal(3)+"");out.println(resultSet.getBigDecimal(4)+"");out.println(resultSet.getBigDecimal(5)+"");out.println(resultSet.getBigDecimal(6)+"");out.println(resultSet.getBigDecimal(7)+"");out.println(resultSet.getBigDecimal(8)+"");out.println(resultSet.getBigDecimal(9)+"");out.println(resultSet.getBigDecimal(10)+"");out.println(resultSet.getBigDecimal(11)+"");out.println(resultSet.getBigDecimal(12)+"");out.println(resultSet.getBigDecimal(13)+"")out.println(resultSet.getBigDecimal(14)+"");out.println(resultSet.getBigDecimal(15)+"");
total = resultSet.getBigDecimal(3).add(resultSet.getBigDecimal(4)).add(resultSet.getBigDecimal(5)).add(resultSet.getBigDecimal(6)).add(resultSet.getBigDecimal(7)).add(resultSet.getBigDecimal(8)).add(resultSet.getBigDecimal(9)).add(resultSet.getBigDecimal(10)).add(resultSet.getBigDecimal(11)).add(resultSet.getBigDecimal(12)).add(resultSet.getBigDecimal(13)).add(resultSet.getBigDecimal(14)).add(resultSet.getBigDecimal(15));
String query1;
query1="UPDATE porcobrar2012 SET total=total";
PreparedStatement ps = connection.prepareStatement(query1);
ps.executeUpdate();
out.println(total);
}
connection.close();
statement.close();
}
catch (Exception e)
{
//e.printStackTrace();
out.println(e.toString());
}
It's because the update closes the existing result set. But I would ask why you aren't doing the addition in a single UPDATE statement without any prior query, at the database, no loops, no BigDecimals. Rule one of database programming is 'don't move the data further than you need to'. It would be many times as efficient to just write "UPDATE porcobrar2012 SET a=b+c+d+...". And you can remove the Class.forName() call too: it hasn't been required for years.