Mnesia write fails - erlang

I defined a record named log. I want to create an mnesia table with name log_table. When I try to write a record to table, I get bad_type error as follows:
(node1#kitt)4> mnesia:create_table(log_table, [{ram_copies, [node()]},
{attributes, record_info(fields, log)}]).
{atomic,ok}
(node1#kitt)5> mnesia:dirty_write(log_table, #log{id="hebelek"}).
** exception exit: {aborted,{bad_type,#log{id = "hebelek"}}}
in function mnesia:abort/1
What am I missing?

By default the record name is assumed to be the same as the table name.
To fix this you should either name your table just log or append the option {record_name, log} in your table options (as you've done in your fix).
It is usually good practice to let your record and table be named the same thing, it makes the code easier to read and debug. You can also then use the mnesia:write/1 function with just your record as only argument. Mnesia then figures out which table to put the record in by looking at the name.

I've found it. When I changed mnesia:create_table call to this
mnesia:create_table(log_table, [{ram_copies, [node()]},
{record_name, log},
{attributes, record_info(fields, log)}]).
everything works OK.

How does your definition of the log-records look? Do you get the same error if you create a new table from scratch (i.e. remove the Mnesia# directory first).

Related

Ruby on Rails - using a block parameter as a method call

I'm having trouble with a little Ruby on Rails I'm building and need some help.
I have a Table with 20+ Columns and a corresponding XML File which can be parsed as some sort of hash with a gem. Every key would be mapped to a column and every value would be a data record in said column.
The way I access a specific value in the already parsed XML file is:
filename["crs","inputkeyhere"]
which returns the value, for example "52" or whatever.
What I am trying to do is upload the file, parse it with the gem and give each column the corresponding value.
My table (or model) is called "Attributeset" and I already know how I can access every column:
#attributeset = Attributeset.new
#attributeset.attributes.keys
So my thought process was:
Iterate over all the keys
Pass every key into a block called |a|
Use the rails possibilty to set attributes by calling the corresponding #attributeset.
Set colum attribute to the corresponding xml key
So my code would go something like this:
#attributeset.attributes.keys.each do |a|
#attributeset.a=filename["crs",a]
end
But my problem is, that ruby thinks ".a" is a method and apparently does not evaluate "a" to the block parameter.
I've read through lambdas and procs and whatnot but didn't really understand how they could work for my specific situation.
Coming from bash scripting maybe my thinking might be wrong but I thought that the .a might get evaluated.
I know I can run the block with yield, but this only works in methods as far as I know..
Any help is appreciated.
Thanks and stay healthy,
Alex
Thanks for the input!
I wanted to make it as clean as possible, and not using any temporary hashes to pass arguments.
I've found the method
write_attribute
which can be used like this:
#attributeset.write_attribute(a, xmp["crs",a])
worked perfectly for me.
You can use []= method to set values dynamically:
#attributeset.attribute_names.each do |attribute|
#attributeset[attribute] = filename["crs", attribute]
end

Neo4j: How to call "CREATE INDEX" only if not exists

The CREATE INDEX <indexName> command is not idempotent and will cause an error if the given index already exists. I'm new to neo4j, and can't find a predicate that avoids this error. I've tried various permutations of ANY(...), and they all barf at "db.indexes()".
Since CREATE INDEX ... fails if the index exists and DROP INDEX ... fails if it doesn't, I don't know how to write a .cypher file that creates the index only if needed.
A short form might be something like CREATE INDEX indexName FOR (c:SomeLabel) ON (c.someProperty) IF NOT EXISTS, but of course that short form doesn't exist.
Is there some way to do this with a predicate, subquery or some such expression?
As of Neo4j 4.1.3, a new index creation syntax has been introduced to do just that
CREATE INDEX myIndex IF NOT EXISTS FOR (t:Test) ON (t.id)
Indexes for search performance
You can use the apoc.schema.node.indexExists function to check whether an index exists before creating it.
For example, this query will create the :Foo(id) index if it does not already exist:
WITH 1 AS ignored
WHERE NOT apoc.schema.node.indexExists('Foo', ['id'])
CALL db.createIndex('index_name', ['Foo'], ['id'], 'native-btree-1.0') YIELD name, labels, properties
RETURN name, labels, properties
For some reason, the Cypher planner currently is not able to parse the normal CREATE INDEX index_name ... syntax after the above WHERE clause, so this query uses the db.createIndex procedure instead.
There is also a much more powerful APOC procedure, apoc.schema.assert, but it may be overkill for your requirements.
By default, the command is ignored if the index exists.
Can you test the following?
CREATE (n:Car {id: 1});
Added 1 label, created 1 node, set 1 property, completed after 23 ms.
CREATE INDEX ON :Car (id);
1st execution: Added 1 index, completed after 6 ms.
2nd execution : (no changes, no records)
I tried both suggestions, and neither solves my issue. I don't have time to discover, through trial-and-error, how to install APOC in my environment.
The first line of mbh86's answer is inaccurate, at least in my system. The command is not ignored, it fails with an error. So if anything else is in the same cypher script, it will fail.
The best I can do is apparently to wrap the CREATE INDEX in a command-line string, run that string from either a bash or python script, run it, and check the return code from the calling program.
I appreciate the effort of both commentators, and I didn't want to leave either hanging.

Cannot delete a mnesia table that I know exists

I have a mnesia table that I am trying to delete. However, when I try to run :mnesia.delete(TableName) I get this error back {:aborted, {:no_exists, TableName}}
When I try to create the same table by running :mnesia.create_table(TableName, [attributes: [:id, :att1, :att2], disc_copies: [Node.self()]]) I get this back {:aborted, {:already_exists, TableName}}
I can still see the .DCD file for the table after a delete, what causes this and how can I fix it?
Note: The code is in an Elixir codebase.
Edit: When my application starts, I try to delete and recreate that table, even if it exists.
:mnesia.delete/1 looks for a key to delete in the given table (and takes a tuple {Table, Key}).
You probably want :mnesia.delete_table/1 which will delete the table itself.
Docs for more: http://erlang.org/doc/man/mnesia.html#delete_table-1

erlang mnesia create table error

I am trying to create mnesia table from Erlang shell. I got error and the same error for the below syntax copied from mnesia help documents.
mnesia:create_table(employee,
[{attributes, record_info(fields, employee)}]).
got the error
record employee undefined
tried various combinations, getting same error. mnesia already started.
You need to have the record employee defined before you can do record_info on it. In the shell use can use rr(FileName). command which will find all the record definitions in the file and remember them. In a module you would either define the record directly in the module or include a file which contains the record definition.
The reason for having to do this special handling in the shell is that records are purely a compile-time feature so a record definition doesn't really "exist" anywhere.
EDIT:
If you want to define the record directly in shell then you can't use the standard -record(...). syntax. That is only valid in modules. The shell sees that as a call to the record/2 function. You need to use the rd shell command. It your case it would become:
3> rd(employee, {emp_no, name, salary, sex, phone, room_no}).
employee
4> record_info(fields, employee).
[emp_no,name,salary,sex,phone,romm_no]
5>
Then record_info works. If you already have the record definitions in a file then use the shell rr(File). command instead as it is easier. I think.
You can try
rd(employee, {emp_no, name, salary, sex, phone, room_no}). in the erlang shell.
rd(RecordName, RecordDefinition) Defines a record in the shell.
RecordName is an atom and RecordDefinition lists the field names and
the default values. Usually record definitions are made known to the
shell by use of the rr commands described below, but sometimes it is
handy to define records on the fly.
Please see this link:http://www.erlang.org/doc/man/shell.html

Rails, Soulmate, Redis remove record

I use Soulmate to autocomplete search results, however I want to be able to delete records after a while so they don't show up in the searchfield again. To reload the list with Soulmate seems a bit hacky and unnecessary.
I have used json to load and I have a unique record "id"
{"id":1547,"term":"Foo Baar, Baaz","score":85}
How can I delete that record from redis so it wont show up in the search results again?
It is not trivial to do it directly from Redis, using redis-cli commands.
Looking at soulmate code, the data structure is as follows:
a soulmate-index:[type] set containing all the prefixes
a soulmate-data:[type] hash object containing the association between the id and the json object.
per prefix, a soulmate-index:[type]:[prefix] sorted set (with score and id)
So to delete an item, you need to:
Retrieve the json object from its id (you already did it) -> id 1547
HDEL soulmate-data:[type] 1547
Generate all the possible prefixes from "Foo Baar, Baaz"
For each prefix:
SREM soulmate-data:[type] [prefix]
ZREM soulmate-index:[type]:[prefix] 1547
Probably it would be easier to directly call the remove method provided in the Soulmate.Loader class from a Ruby script, which automates everything for you.
https://github.com/seatgeek/soulmate/blob/master/lib/soulmate/loader.rb

Resources