2016-07-29 14 views
0

Ich schreibe einen Java-Client, der das Lesen von Daten der Größe einer Million Zeilen testet. Ich filtere die Daten aus dem Schlüssel in der Karte einer Spalte. Der Code erstellt und fügt die Daten ordnungsgemäß ein, kann die Daten jedoch nicht lesen. Mein Code ist:Apache Cassandra Lesen von Daten gibt ReadFailureException

public class MillionMapTest { 
    private Cluster cluster; 
    private Session session; 

    public void connect(String node) { 
     cluster = Cluster.builder().addContactPoint(node).build(); 
     session = cluster.connect(); 
    } 

    public void createSchema() { 
     session.execute("CREATE KEYSPACE xx WITH replication " + 
       "= {'class':'SimpleStrategy', 'replication_factor':3};"); 
     session.execute(
       "CREATE TABLE xx.events (" + 
         "log_time_local timeuuid," + 
         "username text," + 
         "log_type text," + 
         "log_time timestamp," + 
         "device_category text," + 
         "log text," + 
         "priority INT," + 
         "client_ip text," + 
         "backend_app text," + 
         "location_details map<text, text>," + 
         "device_details map<text, text>," + 
         "extra_info Blob," + 
         "PRIMARY KEY (log_time_local, username, log_type)" + 
       ");"); 
     session.execute("CREATE INDEX devicekeys ON xx.events(KEYS(device_details));"); 
    } 

    public void loadData() { 
     PreparedStatement statement = session.prepare(
       "INSERT INTO xx.events VALUES (now(), ?, ?, toTimestamp(now()), ?, ?, ?, ?, ?, ?, ?, ?);"); 
     BoundStatement boundStatement = new BoundStatement(statement); 
     for (int i=0; i<1000000; i++) { 
      Map<String, String> tags = new HashMap<>(); 
      tags.put("os", "ios"); 
      tags.put("category", "tab"); 
      tags.put("dev_num", "12ABF847CA"); 
      if (i % 100 == 0) tags.put("category", "mobile"); 
      session.execute(boundStatement.bind("name_"+i,"type_"+i, "cat_"+i, "log_"+i, i, "ip_"+i, "app_"+i, null, tags, null)); 
     } 
    } 

    public void querySchema() { 
     ResultSet results = session.execute("SELECT * FROM xx.events WHERE device_details['category'] = 'mobile' ALLOW FILTERING;");  
    } 

    public static void main(String[] args) { 
     MillionMapTest client = new MillionMapTest(); 
     client.connect("localhost"); 
     client.createSchema(); 
     client.loadData(); 
     client.querySchema(); 
     session.close(); 
     cluster.close(); 
    } 
} 

Der Fehler ist com.datastax.driver.core.exceptions.ReadFailureException: Cassandra failure during read query at consistency LOCAL_ONE (1 responses were required but only 0 replica responded, 1 failed).

Die Abfrage wird ordnungsgemäß ausgeführt, wenn cqlsh ausgeführt wird, und dieser Code arbeitete mit ein paar Daten. Aber es funktioniert nicht mit einer Million. Was verursacht diesen Fehler und wie behebe ich ihn?

+0

Konnten Sie diese Abfrage von cqlsh ausführen? – Rocherlee

+0

@Rocherlee Ja, es funktioniert von Cqlsh auf dem Cassandra-Server. – khateeb

Antwort

0

Ihr Problem scheint der "Sekundärindex" zu sein. Sie sind nicht die leistungsfähigste Sache in C * und haben ihre eigenen Vorbehalte. Es gibt einige gute Dokumentation über Probleme mit Sekundärindex in C *, z.B. dies link. Sie haben Sekundärindex und das auch auf einem Kartendatentyp. Dies wird langsam sein. Die Tatsache, dass Sie ReadFailureException anstelle von ReadTimeout erhalten, kann etwas damit zu tun haben, dass der Index nicht aktuell ist, wenn Sie ihn abfragen (ich bin mir nicht sicher, aber verweise auf issue, in dem ReadFailureException ausgelöst werden kann).

Ich denke, dass Sie Ihr Schema umgestalten oder die Tabelle denormalisieren sollten und möglicherweise eine Möglichkeit haben, Schlüsselsuchen durchzuführen, anstatt sich auf Sekundärindex zu verlassen.

+0

Ich habe versucht, diese Abfrage auf Cqlsh ausgeführt und es hat funktioniert. Ich habe es mit wenig Daten versucht und es hat funktioniert. Das Problem in der zweiten Verknüpfung wurde in Version 3.1 gelöst. Ich benutze Version 3.7 – khateeb